Merge pull request 'Finish MVP of remoteStorage service pages/UI' (#202) from feature/rs_service_page into master
continuous-integration/drone/push Build is passing
Reviewed-on: #202 Reviewed-by: Greg <greg@noreply.kosmos.org>
No files matched your search
@@ -61,7 +61,7 @@ gem "sentry-rails"
|
||||
# Services
|
||||
gem 'discourse_api'
|
||||
gem "lnurl"
|
||||
gem 'manifique'
|
||||
gem 'manifique', '~> 1.1.0'
|
||||
gem 'nostr', '~> 0.6.0'
|
||||
|
||||
group :development, :test do
|
||||
|
||||
@@ -245,7 +245,7 @@ GEM
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
manifique (1.0.1)
|
||||
manifique (1.1.0)
|
||||
faraday (~> 2.9.0)
|
||||
faraday-follow_redirects (= 0.3.0)
|
||||
nokogiri (~> 1.16.0)
|
||||
@@ -515,7 +515,7 @@ DEPENDENCIES
|
||||
listen (~> 3.2)
|
||||
lnurl
|
||||
lockbox
|
||||
manifique
|
||||
manifique (~> 1.1.0)
|
||||
net-ldap
|
||||
nostr (~> 0.6.0)
|
||||
pagy (~> 6.0, >= 6.0.2)
|
||||
|
||||
@@ -8,8 +8,7 @@ class Services::RemotestorageController < Services::BaseController
|
||||
# unless current_user.service_enabled?(:remotestorage)
|
||||
# redirect_to service_remotestorage_info_path
|
||||
# end
|
||||
@rs_auths = current_user.remote_storage_authorizations
|
||||
# TODO sort by app name
|
||||
# @rs_apps_connected = current_user.remote_storage_authorizations.any?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -3,7 +3,12 @@ class Services::RsAuthsController < Services::BaseController
|
||||
before_action :require_feature_enabled
|
||||
before_action :require_service_available
|
||||
# before_action :require_service_enabled
|
||||
before_action :find_rs_auth
|
||||
before_action :find_rs_auth, only: [:destroy, :launch_app]
|
||||
|
||||
def index
|
||||
@rs_auths = current_user.remote_storage_authorizations
|
||||
# TODO sort by app name?
|
||||
end
|
||||
|
||||
def destroy
|
||||
@auth.destroy!
|
||||
|
||||
@@ -4,7 +4,7 @@ class WellKnownController < ApplicationController
|
||||
def nostr
|
||||
http_status :unprocessable_entity and return if params[:name].blank?
|
||||
domain = request.headers["X-Forwarded-Host"].presence || Setting.primary_domain
|
||||
relay_url = Setting.nostr_relay_url
|
||||
relay_url = Setting.nostr_relay_url.presence
|
||||
|
||||
if params[:name] == "_"
|
||||
# pubkey for the primary domain without a username (e.g. kosmos.org)
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</p>
|
||||
<p>
|
||||
We have run two 6-month trials so far, with the next trial period
|
||||
starting sometime in Q2 2024. Watch your email for notifications about it!
|
||||
starting sometime soon. Watch your email for notifications about it!
|
||||
</p>
|
||||
</section>
|
||||
<% end %>
|
||||
@@ -41,15 +41,16 @@
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if Setting.discourse_enabled? %>
|
||||
<% if Setting.remotestorage_enabled? &&
|
||||
Flipper.enabled?(:remotestorage, current_user) %>
|
||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||
bg-[length:80%] bg-center bg-no-repeat
|
||||
bg-[url(/img/logos/icon_discourse.svg)]">
|
||||
<%= link_to "#{Setting.discourse_public_url}/session/sso?return_path=/",
|
||||
bg-[length:80%] bg-[center_top_-156px] bg-no-repeat
|
||||
bg-[url(/img/logos/icon_remotestorage.svg)]">
|
||||
<%= link_to services_storage_path,
|
||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||
<h3 class="mb-3.5">Discourse</h3>
|
||||
<h3 class="mb-3.5">Storage</h3>
|
||||
<p class="text-gray-600">
|
||||
Community forums and support/help site
|
||||
Sync your data between apps and devices
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -67,16 +68,15 @@
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if Setting.remotestorage_enabled? &&
|
||||
Flipper.enabled?(:remotestorage, current_user) %>
|
||||
<% if Setting.discourse_enabled? %>
|
||||
<div class="border border-gray-300 rounded-md hover:border-gray-400
|
||||
bg-[length:80%] bg-[center_top_-156px] bg-no-repeat
|
||||
bg-[url(/img/logos/icon_remotestorage.svg)]">
|
||||
<%= link_to services_storage_path,
|
||||
bg-[length:80%] bg-center bg-no-repeat
|
||||
bg-[url(/img/logos/icon_discourse.svg)]">
|
||||
<%= link_to "#{Setting.discourse_public_url}/session/sso?return_path=/",
|
||||
class: "block h-full px-6 py-6 rounded-md" do %>
|
||||
<h3 class="mb-3.5">Storage</h3>
|
||||
<h3 class="mb-3.5">Discourse</h3>
|
||||
<p class="text-gray-600">
|
||||
Sync your data between apps and devices
|
||||
Community forums and support/help site
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -2,15 +2,143 @@
|
||||
|
||||
<%= render MainSimpleComponent.new do %>
|
||||
<section>
|
||||
<h3 class="mb-10">Connected Apps</h3>
|
||||
<% if @rs_auths.any? %>
|
||||
<div class="w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-y-10 gap-x-12">
|
||||
<% @rs_auths.each do |auth| %>
|
||||
<%= render RsAuthComponent.new(auth: auth) %>
|
||||
<% end %>
|
||||
<p class="mb-6">
|
||||
Store and synchronize your app data across different devices.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<%= render partial: "shared/tabnav_remotestorage" %>
|
||||
|
||||
<section>
|
||||
<h3>Your Storage Address</h3>
|
||||
<p class="mb-6">
|
||||
In order to connect an app to your storage account, give it your address:
|
||||
</p>
|
||||
<p data-controller="clipboard" class="flex gap-1 sm:w-2/5">
|
||||
<input type="text" id="user_address" class="grow"
|
||||
value=<%= current_user.address %> disabled="disabled"
|
||||
data-clipboard-target="source" />
|
||||
<button id="copy-user-address" class="btn-md btn-icon btn-outline shrink-0"
|
||||
data-clipboard-target="trigger" data-action="clipboard#copy"
|
||||
title="Copy to clipboard">
|
||||
<span class="content-initial">
|
||||
<%= render partial: "icons/copy", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||
</span>
|
||||
<span class="content-active hidden">
|
||||
<%= render partial: "icons/check", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||
</span>
|
||||
</button>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Recommended Apps</h3>
|
||||
<div data-controller="tabs"
|
||||
data-tabs-active-tab-class="-mb-px border-gray-200 border-l border-t border-r rounded-t text-indigo-600 hover:text-indigo-600"
|
||||
data-tabs-inactive-tab-class="text-gray-500 hover:text-gray-700"
|
||||
class="mb-12">
|
||||
<select data-action="tabs#change" data-tabs-target="select"
|
||||
class="block w-full mb-8 sm:hidden">
|
||||
<option>Productivity</option>
|
||||
<option>Bookmarks</option>
|
||||
<option>Reading</option>
|
||||
<option>File sharing</option>
|
||||
<option>Learning</option>
|
||||
</select>
|
||||
<ul class="hidden sm:flex list-reset mb-8 border-gray-200 border-b">
|
||||
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||
Productivity
|
||||
</a>
|
||||
</li>
|
||||
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||
Bookmarks
|
||||
</a>
|
||||
</li>
|
||||
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||
Reading
|
||||
</a>
|
||||
</li>
|
||||
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||
File sharing
|
||||
</a>
|
||||
</li>
|
||||
<li class="mr-2" data-tabs-target="tab" data-action="click->tabs#change:prevent">
|
||||
<a href="#" class="bg-white inline-block py-2 px-4 font-semibold no-underline">
|
||||
Learning
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Hyperdraft",
|
||||
description: "Create text notes and (optionally) turn them into a website",
|
||||
icon_path: "/img/app_icons/hyperdraft.png",
|
||||
links: [
|
||||
["Web App", "https://hyperdraft.rosano.ca"],
|
||||
]
|
||||
) %>
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Notes Together",
|
||||
description: "A powerful note-taking app, with support for attaching images and other files",
|
||||
icon_path: "/img/app_icons/notes-together.png",
|
||||
links: [
|
||||
["Web App", "https://notestogether.hominidsoftware.com"],
|
||||
]
|
||||
) %>
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Papiers",
|
||||
description: "A simple note-taking app",
|
||||
icon_path: "/img/app_icons/papiers.png",
|
||||
links: [
|
||||
["Web App", "https://papiers.gitlab.io"],
|
||||
]
|
||||
) %>
|
||||
</div>
|
||||
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Webmarks",
|
||||
description: "Archive your bookmarks in your remote storage",
|
||||
icon_path: "/img/app_icons/webmarks.png",
|
||||
links: [
|
||||
["Web App", "https://webmarks.5apps.com"],
|
||||
]
|
||||
) %>
|
||||
</div>
|
||||
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Pétrolette",
|
||||
description: "A news aggregator that syncs with your remote storage",
|
||||
icon_path: "/img/app_icons/petrolette.png",
|
||||
links: [
|
||||
["Web App", "https://petrolette.space"],
|
||||
]
|
||||
) %>
|
||||
</div>
|
||||
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Sharesome",
|
||||
description: "Quickly and easily share files from your remote storage",
|
||||
icon_path: "/img/app_icons/sharesome.png",
|
||||
links: [
|
||||
["Web App", "https://sharesome.5apps.com"],
|
||||
]
|
||||
) %>
|
||||
</div>
|
||||
<div class="hidden grid grid-cols-1 gap-6" data-tabs-target="panel">
|
||||
<%= render AppInfoComponent.new(
|
||||
name: "Kommit",
|
||||
description: "Create flashcards and learn them with spaced-repetition",
|
||||
icon_path: "/img/app_icons/kommit.png",
|
||||
links: [
|
||||
["Web App", "https://kommit.rosano.ca"],
|
||||
]
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<p>No apps connected yet.</p>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
@@ -0,0 +1,33 @@
|
||||
<%= render HeaderComponent.new(title: "Storage") %>
|
||||
|
||||
<%= render MainSimpleComponent.new do %>
|
||||
<section>
|
||||
<p class="mb-6">
|
||||
Store and synchronize your app data across different devices.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<%= render partial: "shared/tabnav_remotestorage" %>
|
||||
|
||||
<section>
|
||||
<% if @rs_auths.any? %>
|
||||
<div class="w-full grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-y-10 gap-x-12 mt-4">
|
||||
<% @rs_auths.each do |auth| %>
|
||||
<%= render RsAuthComponent.new(auth: auth) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-center">
|
||||
<p class="mt-4 mb-12 inline-flex align-center items-center">
|
||||
<%= image_tag("/img/illustrations/undraw_friends_r511.svg", class: 'h-48') %>
|
||||
</p>
|
||||
<h3>
|
||||
No apps connected
|
||||
</h3>
|
||||
<p class="text-gray-500">
|
||||
When connected, your apps will show up here.
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
</section>
|
||||
<% end %>
|
||||
@@ -0,0 +1,14 @@
|
||||
<section>
|
||||
<div class="border-b border-gray-200">
|
||||
<nav class="-mb-px flex" aria-label="Tabs">
|
||||
<%= render TabnavLinkComponent.new(
|
||||
name: "Info", path: services_storage_path,
|
||||
active: current_page?(services_storage_path)
|
||||
) %>
|
||||
<%= render TabnavLinkComponent.new(
|
||||
name: "Connected Apps", path: apps_services_storage_path,
|
||||
active: current_page?(apps_services_storage_path)
|
||||
) %>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
@@ -48,7 +48,8 @@ Rails.application.routes.draw do
|
||||
end
|
||||
|
||||
resource :storage, controller: 'remotestorage', only: [:show] do
|
||||
resources :rs_auths, only: [:destroy] do
|
||||
get :apps, to: "rs_auths#index"
|
||||
resources :rs_auths, only: [:index, :destroy] do
|
||||
member do
|
||||
get :revoke, to: 'rs_auths#destroy'
|
||||
get :launch_app
|
||||
|
||||
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1 @@
|
||||
<svg data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="786.29468" height="749.1971" viewBox="0 0 786.29468 749.1971" xmlns:xlink="http://www.w3.org/1999/xlink"><title>friends</title><ellipse cx="428.29468" cy="670.89024" rx="358" ry="40" fill="#3f3d56"/><path d="M812.69445,702.0311l6.17411,19.02315s29.736,30.72079,18.98128,39.04755-34.884-35.56837-34.884-35.56837l-4.447-21.47613Z" transform="translate(-206.85266 -75.40145)" fill="#ffb8b8"/><path d="M755.64734,554.79169l9-3s14,4,16,18,17,85,17,85,6,3,2,8,20,50,20,50l-19,9s-38-40-38-44,1-8,1-12-1-4,0-7a32.16669,32.16669,0,0,0,1-8l-7-16Z" transform="translate(-206.85266 -75.40145)" fill="#00bfa6"/><ellipse cx="90.41777" cy="363.49768" rx="90.41777" ry="184.48877" fill="#00bfa6"/><path d="M296.44031,440.81268c4.51025-80.30664,13.59765-134.55127,13.689-135.08984l-1.97168-.334c-.09131.53907-9.19482,54.87061-13.7124,135.28077-4.16894,74.21386-5.1748,186.46679,13.71192,299.78613l1.97265-.32813C291.27527,627.00067,292.27869,514.91766,296.44031,440.81268Z" transform="translate(-206.85266 -75.40145)" fill="#3f3d56"/><rect x="291.31649" y="423.24475" width="92.72517" height="2.00012" transform="translate(-367.08716 134.1508) rotate(-28.1569)" fill="#3f3d56"/><rect x="250.38166" y="399.80166" width="2.00012" height="92.72517" transform="translate(-467.45648 381.99296) rotate(-61.8584)" fill="#3f3d56"/><ellipse cx="304.56511" cy="252.45832" rx="123.72957" ry="252.45832" fill="#e6e6e6"/><path d="M509.91492,330.446c6.17285-109.91113,18.61084-184.15185,18.73584-184.88916l-1.97168-.334c-.125.73779-12.5791,75.06543-18.75928,185.08008-5.70459,101.53759-7.08057,255.11767,18.75879,410.15283l1.97266-.32813C502.84412,585.28387,504.21814,431.87469,509.91492,330.446Z" transform="translate(-206.85266 -75.40145)" fill="#3f3d56"/><rect x="503.27009" y="306.80628" width="126.88732" height="2.00012" transform="translate(-285.03704 228.45225) rotate(-28.1571)" fill="#3f3d56"/><rect x="447.62287" y="274.35779" width="2.00012" height="126.88732" transform="translate(-267.69188 498.66399) rotate(-61.8584)" fill="#3f3d56"/><ellipse cx="201.49146" cy="508.96817" rx="46.22863" ry="94.32509" fill="#e6e6e6"/><path d="M408.30341,588.43341l.27362.5116,41.79785-22.37207-.94336-1.76368-41.041,21.967c2.27112-41.80139,6.91614-69.86267,7.00977-70.41522l-1.97168-.334c-.10223.60339-5.62122,33.92651-7.58014,82.1449L364.455,576.0163,363.5116,577.78,405.30945,600.152l.499-.9328c-1.56732,39.79736-.68884,89.55963,7.61969,139.41034l1.97266-.32813C406.3421,683.949,406.14258,629.69867,408.30341,588.43341Z" transform="translate(-206.85266 -75.40145)" fill="#3f3d56"/><path d="M767.8838,459.86565c-16.07417-27.39543-47.87565-28.67218-47.87565-28.67218s-30.98872-3.9971-50.86779,37.72647c-18.52888,38.88981-44.1011,76.4387-4.11692,85.54252l7.2223-22.67357,4.47274,24.3616a155.1105,155.1105,0,0,0,17.10774.29491c42.81983-1.39444,83.59924.408,82.2862-15.09055C774.367,520.75175,783.35039,486.22553,767.8838,459.86565Z" transform="translate(-206.85266 -75.40145)" fill="#2f2e41"/><path d="M655.84213,679.30051a61.23955,61.23955,0,0,1-1.94921,8.4635c-.95617,2.712-2.4324,5.22006-3.30667,7.96-2.78678,8.73379,1.07652,18.47175,7.24682,25.21311a40.722,40.722,0,0,0,19.88743,11.91139c5.56641,1.41209,11.35417,1.61532,17.09064,1.81153,15.88459.54331,32.17788,1.02938,47.22947-4.11969a81.7199,81.7199,0,0,0,13.72159-6.28756,10.2875,10.2875,0,0,0,3.56045-2.82771c1.148-1.64851,1.29485-3.78648,1.28483-5.801-.03378-6.79217-1.39894-13.5497-1.07481-20.33408.17953-3.75786.87679-7.51282.53357-11.25908a20.71019,20.71019,0,0,0-15.73776-17.89186c-4.2698-.92484-8.69846-.42089-13.04555.00071a329.78922,329.78922,0,0,1-33.95148,1.53123c-11.58212-.07457-23.09272-1.85786-34.61719-2.04411-3.40812-.05507-3.33927,1.00471-4.42429,4.33169A81.60486,81.60486,0,0,0,655.84213,679.30051Z" transform="translate(-206.85266 -75.40145)" fill="#2f2e41"/><path d="M610.5518,673.78022a33.98929,33.98929,0,0,0-9.533-1.02218,24.06038,24.06038,0,0,0-17.379,9.11386,24.49135,24.49135,0,0,0-4.71053,19.17721,40.53261,40.53261,0,0,0,3.77749,10.41167c2.52818,5.17506,5.56038,10.33824,10.2407,13.65454a39.73688,39.73688,0,0,0,9.0377,4.33923l24.6503,9.36656c3.62634,1.37793,7.25322,2.75606,10.91545,4.03375a211.89949,211.89949,0,0,0,57.01276,11.43233c5.919.35552,11.92757.45444,17.70188-.90474a5.749,5.749,0,0,0,3.62532-1.97555,6.30178,6.30178,0,0,0,.81-2.69858l1.51685-10.7108a9.04669,9.04669,0,0,0-.12893-4.51521c-.69486-1.80009-2.43661-2.93247-4.09733-3.89455-16.20583-9.38838-35.12808-14.56788-48.76876-27.45327-3.21124-3.03343-5.89853-7.84172-9.80015-9.90227-4.42438-2.33663-9.63493-3.67023-14.20814-5.82341C631.21684,681.70171,621.38727,676.29253,610.5518,673.78022Z" transform="translate(-206.85266 -75.40145)" fill="#2f2e41"/><path d="M635.16155,688.21992c8.71284,2.75379,45.4985,21.83206,51.80367,28.49317-.84515.30714-29.52024-15.90188-30.38066-16.16235-7.8213-2.36765-15.68608-4.75084-23.11356-8.2158-1.49421-.697-9.70725-3.97339-9.3353-5.875C624.55541,684.31414,633.61478,687.73105,Line truncated
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -47,6 +47,10 @@ RSpec.describe "Well-known URLs", type: :request do
|
||||
end
|
||||
|
||||
context "without relay configured" do
|
||||
before do
|
||||
Setting.nostr_relay_url = ""
|
||||
end
|
||||
|
||||
it "does not include a recommended relay" do
|
||||
get "/.well-known/nostr.json?name=bobdylan"
|
||||
res = JSON.parse(response.body)
|
||||
|
||||
@@ -4,6 +4,10 @@ RSpec.describe NostrManager::PublishZapReceipt, type: :model do
|
||||
let(:user) { create :user, ln_account: "123456abcdef" }
|
||||
let(:zap) { create :zap, user: user }
|
||||
|
||||
before do
|
||||
Setting.nostr_relay_url = ""
|
||||
end
|
||||
|
||||
describe "Default/delayed execution" do
|
||||
it "publishes zap receipts to all requested relays" do
|
||||
expect(NostrPublishEventJob).to receive(:perform_later)
|
||||
|
||||