WIP Relay editing UI

This commit is contained in:
2026-08-11 19:45:07 -06:00
parent a9045fa413
commit 407d9f633e
5 changed files with 137 additions and 32 deletions
@@ -0,0 +1,45 @@
<div class="w-[72vw] md:w-[500px]">
<h3 class="mb-6">Edit relays</h3>
<%= form_with url: "#", local: true,
html: { data: { controller: "relay-list-editor" } } do |f| %>
<ul data-relay-list-editor-target="list" class="mb-4 space-y-2">
<% @relays.each do |relay| %>
<li class="flex gap-x-2 items-center">
<input type="text" name="relay_urls[]" value="<%= relay[:url] %>" class="grow" />
<select name="relay_markers[]" class="shrink-0 w-32">
<option value=""<%= %( selected="selected") if relay[:marker].nil? %>>Read & write</option>
<option value="read"<%= %( selected="selected") if relay[:marker] == "read" %>>Read only</option>
<option value="write"<%= %( selected="selected") if relay[:marker] == "write" %>>Write only</option>
</select>
<button type="button" class="btn-md btn-icon btn-outline text-red-700 shrink-0"
data-action="click->relay-list-editor#remove" title="Remove relay">
<%= render partial: "icons/trash-2", locals: { custom_class: "h-4 w-4" } %>
</button>
</li>
<% end %>
</ul>
<template data-relay-list-editor-target="template">
<li class="flex gap-x-2 items-center">
<input type="text" name="relay_urls[]" value="" class="grow" />
<select name="relay_markers[]" class="shrink-0 w-32">
<option value="">Read & write</option>
<option value="read">Read only</option>
<option value="write">Write only</option>
</select>
<button type="button" class="btn-md btn-icon btn-outline text-red-700 shrink-0"
data-action="click->relay-list-editor#remove" title="Remove relay">
<%= render partial: "icons/trash-2", locals: { custom_class: "h-4 w-4" } %>
</button>
</li>
</template>
<button type="button" class="btn-md btn-gray w-full mb-6"
data-action="click->relay-list-editor#add">
<%= render partial: "icons/plus", locals: { custom_class: "h-4 w-4 inline mr-1" } %>
Add relay
</button>
<%= f.submit "Save relay list", class: "btn-md btn-blue w-full" %>
<% end %>
</div>
@@ -0,0 +1,31 @@
# frozen_string_literal: true
module Settings
class NostrEditRelaysComponent < ViewComponent::Base
def initialize(nip65_event: nil)
@nip65_event = nip65_event
@relays = build_relays
ensure_site_relay
end
private
def build_relays
if @nip65_event.present?
@nip65_event["tags"]
.select { |t| t[0] == "r" }
.map { |t| { url: t[1], marker: t[2] } }
else
Setting.nostr_discovery_relays.map { |url| { url: url, marker: nil } }
end
end
def ensure_site_relay
site_relay_url = Setting.nostr_relay_url
return if site_relay_url.blank?
@relays.reject! { |r| r[:url] == site_relay_url }
@relays.unshift({ url: site_relay_url, marker: nil })
end
end
end
@@ -1,18 +1,18 @@
<%= render StatusTextComponent.new( <% @statuses.each do |status| %>
text: @text, <%= render StatusTextComponent.new(
icon_name: @icon_name, text: status[:text],
icon_color: @icon_color) %> icon_name: status[:icon_name],
icon_color: status[:icon_color]
<% if @status == 1 %> ) %>
<p class="mt-8">
<button class="btn-md btn-blue">
Add the relay to my list
</button>
</p>
<% elsif @status == 2 %>
<p class="mt-8">
<button class="btn-md btn-blue">
Set up default relays
</button>
</p>
<% end %> <% end %>
<div class="mt-8" data-controller="modal" data-action="keydown.esc->modal#close">
<button data-action="click->modal#open" class="btn-md btn-blue w-full sm:w-auto">
<%= @button_text %>
</button>
<%= render ModalComponent.new(show_close_button: false) do %>
<%= render Settings::NostrEditRelaysComponent.new(
nip65_event: @nip65_event
) %>
<% end %>
</div>
@@ -3,34 +3,46 @@
module Settings module Settings
class NostrRelayStatusComponent < ViewComponent::Base class NostrRelayStatusComponent < ViewComponent::Base
def initialize(nip65_event:, relay_url: Setting.nostr_relay_url) def initialize(nip65_event:, relay_url: Setting.nostr_relay_url)
@nip65_event = nip65_event
@relay_url = relay_url @relay_url = relay_url
@relay_host = relay_url.present? ? URI.parse(relay_url).host : nil
@statuses = []
if nip65_event.present? if nip65_event.present?
@statuses.push({
text: "You have a relay list configured",
icon_name: "check-circle",
icon_color: "emerald-500"
})
if relay_urls(nip65_event).include?(@relay_url) if relay_urls(nip65_event).include?(@relay_url)
@text = "You have a relay list, and the Kosmos relay is part of it" @statuses.push({
@icon_name = "check-circle" text: "The <strong>#{@relay_host}</strong> relay is part of your relay list",
@icon_color = "emerald-500" icon_name: "check-circle",
@status = 0 icon_color: "emerald-500"
})
else else
@text = "The Kosmos relay is missing from your relay list" @statuses.push({
@icon_name = "alert-octagon" text: "The <strong>#{@relay_host}</strong> relay is missing from your relay list",
@icon_color = "amber-500" icon_name: "alert-octagon",
@status = 1 icon_color: "amber-500"
})
end end
else else
@text = "We could not find a relay list for your public key" @statuses.push({
@icon_name = "alert-octagon" text: "We could not find a relay list for your public key",
@icon_color = "amber-500" icon_name: "alert-octagon",
@status = 2 icon_color: "amber-500"
})
end end
@button_text = (nip65_event.present? ? "Edit relays" : "Set up relays")
end end
private private
def relay_urls(nip65_event) def relay_urls(nip65_event)
nip65_event["tags"].select{ |t| t[0] == "r" }.map{ |t| t[1] } nip65_event["tags"].select { |t| t[0] == "r" }.map { |t| t[1] }
# @inbox_relay_urls = relay_tags&.select{ |t| t[2] == "read" }&.map{ |t| t[1] }
# @outbox_relay_urls = relay_tags&.select{ |t| t[2] != "read" }&.map{ |t| t[1] }
end end
end end
end end
@@ -0,0 +1,17 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = [ "list", "template" ]
add (event) {
event.preventDefault()
const row = this.templateTarget.content.cloneNode(true)
this.listTarget.appendChild(row)
}
remove (event) {
event.preventDefault()
const row = event.target.closest("li")
row.remove()
}
}