Hide Nostr publishing settings when no account connected
CI / Lint (pull_request) Successful in 1m11s
CI / Test (pull_request) Successful in 1m30s
Release Drafter / Update release notes draft (pull_request) Successful in 15s

This commit is contained in:
2026-09-17 22:24:51 +02:00
parent 6ba2f1d132
commit 75c0862134
2 changed files with 137 additions and 97 deletions
+100 -97
View File
@@ -20,6 +20,7 @@ const stripProtocol = (url) => (url ? url.replace(/^wss?:\/\//, '') : '');
export default class AppMenuSettingsNostr extends Component {
@service settings;
@service nostrData;
@service nostrAuth;
@service toast;
@tracked newReadRelay = '';
@@ -367,109 +368,111 @@ export default class AppMenuSettingsNostr extends Component {
{{/if}}
</div>
<div class="form-group">
<label for="new-write-relay">Write Relays</label>
<ul class="relay-list">
{{#each this.writeRelaysForDisplay as |relay|}}
<li>
<span>{{stripProtocol relay.url}}</span>
<div class="relay-actions">
<button
type="button"
class="btn-remove-relay"
aria-label="Remove"
aria-description={{if
relay.isRequired
"Required relays cannot be removed"
"Remove relay"
}}
disabled={{relay.isRequired}}
{{tooltip}}
{{on "click" (fn this.removeWriteRelay relay.url)}}
>
<Icon @name="x" @size={{14}} @color="currentColor" />
</button>
</div>
</li>
{{/each}}
</ul>
<div class="add-relay-input">
<input
id="new-write-relay"
type="text"
class="form-control"
placeholder="relay.example.com"
value={{this.newWriteRelay}}
{{on "input" this.updateNewWriteRelay}}
{{on "keydown" this.handleWriteRelayKeydown}}
/>
<button
type="button"
class="btn btn-secondary"
{{on "click" this.addWriteRelay}}
>Add</button>
</div>
{{#if this.hasWriteOverrides}}
<button
type="button"
class="btn-link reset-relays"
{{on "click" this.resetWriteRelays}}
>
Reset to Defaults
</button>
{{/if}}
</div>
<div class="form-group">
<label for="nostr-media-server">Media server</label>
<select
id="nostr-media-server"
class="form-control"
{{on "change" (fn @onChange "nostrMediaServer")}}
>
{{#each this.mediaServerOptions as |server|}}
<option
value={{server}}
selected={{if
(eq server this.settings.nostrMediaServer)
"selected"
}}
>
{{server}}
</option>
{{/each}}
</select>
</div>
{{#if this.hasMultipleMediaServers}}
{{#if this.nostrAuth.isConnected}}
<div class="form-group">
<label for="nostr-photo-fallback-uploads">Upload photos to fallback
servers</label>
<label for="new-write-relay">Write Relays</label>
<ul class="relay-list">
{{#each this.writeRelaysForDisplay as |relay|}}
<li>
<span>{{stripProtocol relay.url}}</span>
<div class="relay-actions">
<button
type="button"
class="btn-remove-relay"
aria-label="Remove"
aria-description={{if
relay.isRequired
"Required relays cannot be removed"
"Remove relay"
}}
disabled={{relay.isRequired}}
{{tooltip}}
{{on "click" (fn this.removeWriteRelay relay.url)}}
>
<Icon @name="x" @size={{14}} @color="currentColor" />
</button>
</div>
</li>
{{/each}}
</ul>
<div class="add-relay-input">
<input
id="new-write-relay"
type="text"
class="form-control"
placeholder="relay.example.com"
value={{this.newWriteRelay}}
{{on "input" this.updateNewWriteRelay}}
{{on "keydown" this.handleWriteRelayKeydown}}
/>
<button
type="button"
class="btn btn-secondary"
{{on "click" this.addWriteRelay}}
>Add</button>
</div>
{{#if this.hasWriteOverrides}}
<button
type="button"
class="btn-link reset-relays"
{{on "click" this.resetWriteRelays}}
>
Reset to Defaults
</button>
{{/if}}
</div>
<div class="form-group">
<label for="nostr-media-server">Media server</label>
<select
id="nostr-photo-fallback-uploads"
id="nostr-media-server"
class="form-control"
{{on "change" (fn @onChange "nostrPhotoFallbackUploads")}}
{{on "change" (fn @onChange "nostrMediaServer")}}
>
<option
value="true"
selected={{if
this.settings.nostrPhotoFallbackUploads
"selected"
}}
>
Yes
</option>
<option
value="false"
selected={{unless
this.settings.nostrPhotoFallbackUploads
"selected"
}}
>
No
</option>
{{#each this.mediaServerOptions as |server|}}
<option
value={{server}}
selected={{if
(eq server this.settings.nostrMediaServer)
"selected"
}}
>
{{server}}
</option>
{{/each}}
</select>
</div>
{{#if this.hasMultipleMediaServers}}
<div class="form-group">
<label for="nostr-photo-fallback-uploads">Upload photos to
fallback servers</label>
<select
id="nostr-photo-fallback-uploads"
class="form-control"
{{on "change" (fn @onChange "nostrPhotoFallbackUploads")}}
>
<option
value="true"
selected={{if
this.settings.nostrPhotoFallbackUploads
"selected"
}}
>
Yes
</option>
<option
value="false"
selected={{unless
this.settings.nostrPhotoFallbackUploads
"selected"
}}
>
No
</option>
</select>
</div>
{{/if}}
{{/if}}
<div class="form-group">
@@ -2,6 +2,7 @@ import { module, test } from 'qunit';
import { setupRenderingTest } from 'marco/tests/helpers';
import { click, fillIn, render, settled } from '@ember/test-helpers';
import Service, { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import AppMenuSettingsNostr from 'marco/components/app-menu/settings/nostr';
import {
excludeRequiredRelays,
@@ -67,6 +68,10 @@ class MockNostrDataService extends Service {
async clearCache() {}
}
class MockNostrAuthService extends Service {
@tracked isConnected = true;
}
function readRows(element) {
const list = element.querySelectorAll('.relay-list')[0];
return [...list.querySelectorAll('li')];
@@ -88,6 +93,7 @@ module('Integration | Component | app-menu/settings/nostr', function (hooks) {
localStorage.removeItem('marco:settings');
this.owner.register('service:nostrData', MockNostrDataService);
this.owner.register('service:nostrAuth', MockNostrAuthService);
this.settings = this.owner.lookup('service:settings');
this.onChange = () => {};
});
@@ -283,6 +289,37 @@ module('Integration | Component | app-menu/settings/nostr', function (hooks) {
);
});
test('publish-only settings are hidden when no nostr key is connected', async function (assert) {
this.owner.lookup('service:nostrAuth').isConnected = false;
const element = await renderAndOpenDetails(this);
assert.dom('#new-write-relay').doesNotExist('write relay input hidden');
assert
.dom('#nostr-media-server')
.doesNotExist('media server select hidden');
assert
.dom('#nostr-photo-fallback-uploads')
.doesNotExist('fallback uploads select hidden');
assert.strictEqual(
element.querySelectorAll('.relay-list').length,
1,
'only the read relay list is rendered'
);
});
test('read relays and cached data stay visible when no nostr key is connected', async function (assert) {
this.owner.lookup('service:nostrAuth').isConnected = false;
const element = await renderAndOpenDetails(this);
assert.dom('#new-read-relay').exists('read relay input visible');
assert.dom(readRows(element)[0]).exists('read relay list visible');
assert
.dom(element.querySelector('.btn-outline'))
.includesText('Clear profiles, photos, and reviews');
});
test('tooltip appears on hover and disappears on mouseleave', async function (assert) {
const element = await renderAndOpenDetails(this);
const mailboxRow = rowByText(readRows(element), 'mailbox.example.com');