Compare commits
No commits in common. "5635f7910a342a0ec9b187643b45cb7f650520d5" and "f29d4f94a05eab9ee694130cff4e1c1ddd46efa1" have entirely different histories.
5635f7910a
...
f29d4f94a0
7 changed files with 159 additions and 212 deletions
|
|
@ -6,14 +6,13 @@ verified green at the moment this file was written.
|
||||||
## Where things are
|
## Where things are
|
||||||
|
|
||||||
- Project: `/home/avi/Projects/Nostr_Keynctr`
|
- Project: `/home/avi/Projects/Nostr_Keynctr`
|
||||||
- Git repo: `master` @ `835b0a0` ("frontend: list all profiles on Home, pin
|
- Git repo: `master` @ `fa5ba08` ("Security: upgrade nostr stack 0.40->0.45
|
||||||
dev host, widen profiles card"). Before it: `71e580f` (Trim white margins
|
clearing 11 RustSec advisories"). Before it: `bf10ae3` (Checkpoint: clarify
|
||||||
from sidebar logo artwork), `f29d4f9` (Checkpoint 0.45 migration),
|
NIP-42 status), `e210f17` (Checkpoint: DRY modal save lifecycle / R3),
|
||||||
`fa5ba08` (Security: upgrade nostr stack 0.40->0.45), `bf10ae3`, `e210f17`,
|
`7098e75` (refactor: share modal save lifecycle), `e6a1efc` (R4),
|
||||||
`7098e75`, `e6a1efc`, `6d5063d`, `1c428a9`.
|
`6d5063d` (R2), `1c428a9` (R1).
|
||||||
- Working tree: still DIRTY with the long-standing user changes — `concept3.svg`
|
- Working tree: only the long-standing user changes remain — `concept3.svg`
|
||||||
deleted, `KeynectrAppIconPossibility02.jpeg` untracked. These are NOT part
|
deleted, `KeynectrAppIconPossibility02.jpeg` untracked.
|
||||||
of the frontend commit above and remain uncommitted.
|
|
||||||
|
|
||||||
## What was completed
|
## What was completed
|
||||||
|
|
||||||
|
|
@ -42,7 +41,6 @@ verified green at the moment this file was written.
|
||||||
|
|
||||||
## Commits added most recently
|
## Commits added most recently
|
||||||
|
|
||||||
- `835b0a0` frontend: list all profiles on Home, pin dev host, widen profiles card
|
|
||||||
- `fa5ba08` Security: upgrade nostr stack 0.40->0.45 clearing 11 RustSec advisories
|
- `fa5ba08` Security: upgrade nostr stack 0.40->0.45 clearing 11 RustSec advisories
|
||||||
|
|
||||||
## Verification commands run (all green)
|
## Verification commands run (all green)
|
||||||
|
|
@ -1351,76 +1349,3 @@ $B rename <npub> <new-name> # rename + publish the new name
|
||||||
- Relay config at time of writing (all enabled): nos.lol, relay.primal.net, l484.com
|
- Relay config at time of writing (all enabled): nos.lol, relay.primal.net, l484.com
|
||||||
(user's own), damus.io, snort.social, soloco.nl; relay.nostr.band added but was
|
(user's own), damus.io, snort.social, soloco.nl; relay.nostr.band added but was
|
||||||
unreachable (handshake timeout) — retry enabling later.
|
unreachable (handshake timeout) — retry enabling later.
|
||||||
|
|
||||||
## Checkpoint — frontend home screen improvements (2026-08-26)
|
|
||||||
|
|
||||||
A stopping point you can return to if this session is closed.
|
|
||||||
|
|
||||||
### Where things are
|
|
||||||
|
|
||||||
- Project: `/home/avi/Projects/Nostr_Keynctr`
|
|
||||||
- Git repo: `master`. **Working tree is DIRTY** — the changes below are local
|
|
||||||
edits and have NOT been committed yet (see "outstanding items").
|
|
||||||
- Dev-run fix also applied: `frontend/vite.config.ts` now binds the dev server
|
|
||||||
to `host: '127.0.0.1'` so Electron (`NOSTR_GUI_DEV_URL=http://127.0.0.1:5173`)
|
|
||||||
and Vite agree on address and the window is no longer a white box.
|
|
||||||
|
|
||||||
### What was completed (user-facing)
|
|
||||||
|
|
||||||
1. **Profile pictures now show on Home.** The Home screen's active-profile
|
|
||||||
`Avatar` was missing the `picture` prop, so the image only appeared on the
|
|
||||||
Profiles screen. `HomeScreen.tsx` now passes `picture={profile.picture}`.
|
|
||||||
2. **All profiles listed on Home.** Replaced the single "Active profile" card
|
|
||||||
with a "Your profiles" card listing every profile (avatar + picture, label,
|
|
||||||
shortened npub, Active badge). Each non-active row has a working **Select**
|
|
||||||
button (calls `selectProfile`); a **Manage** link goes to the Profiles
|
|
||||||
screen and an **Add profile** button is at the bottom.
|
|
||||||
3. **`Badge` now accepts `className`** so the Active badge can be inline next to
|
|
||||||
the name.
|
|
||||||
4. **Relays card removed from Home.** The "Relays" card (live connection status,
|
|
||||||
refresh, "enable a relay" link) is no longer shown on Home — relay status
|
|
||||||
lives on the Relays screen. Removed the now-unused relay-check logic
|
|
||||||
(`relayTest`/`runCheck`/`statuses`/`testing`/`enabled`/`Spinner`) and the
|
|
||||||
corresponding test.
|
|
||||||
5. **Profile card now full-width on Home.** `.home-grid` was a two-column grid
|
|
||||||
(profiles + relays); with Relays gone the profiles card only filled the left
|
|
||||||
half. Changed it to a single `1fr` column and dropped the now-redundant
|
|
||||||
`@media (max-width: 900px)` override, so "Your profiles" matches the width
|
|
||||||
of "Most recent publication" below it. No JSX change.
|
|
||||||
|
|
||||||
### Files changed
|
|
||||||
|
|
||||||
- `frontend/src/screens/HomeScreen.tsx` (profiles list + picture prop + select; relays removed)
|
|
||||||
- `frontend/src/components/Badge.tsx` (add `className` prop)
|
|
||||||
- `frontend/src/styles.css` (`.home-profile-list` / `.home-profile-row` / etc.)
|
|
||||||
- `frontend/src/test/HomeScreen.test.tsx` (scope copy-button test to Alice's row; drop relay-status test)
|
|
||||||
- `frontend/vite.config.ts` (dev server `host: '127.0.0.1'`)
|
|
||||||
|
|
||||||
### Verification commands run (all green)
|
|
||||||
|
|
||||||
Frontend (`frontend/`): `npm run typecheck` clean; `npm run lint` clean;
|
|
||||||
`npm test` 15 files / 98 tests pass; `npm run format:check` clean (after
|
|
||||||
`npm run format`).
|
|
||||||
|
|
||||||
### How to use / reproduce
|
|
||||||
|
|
||||||
Dev mode (two terminals, from `~/Projects/Nostr_Keynctr/frontend`):
|
|
||||||
|
|
||||||
```
|
|
||||||
# Terminal 1
|
|
||||||
npm run dev # prints Local: http://127.0.0.1:5173/
|
|
||||||
|
|
||||||
# Terminal 2
|
|
||||||
NOSTR_GUI_DEV_URL=http://127.0.0.1:5173 npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
Home now shows every profile with its picture, and selecting one there updates
|
|
||||||
the active profile immediately.
|
|
||||||
|
|
||||||
### Outstanding items
|
|
||||||
|
|
||||||
- Committed as `835b0a0`. The working tree still has unrelated user changes
|
|
||||||
(`concept3.svg` deleted, `KeynectrAppIconPossibility02.jpeg` untracked) that
|
|
||||||
were intentionally left out of the commit.
|
|
||||||
- The dev-server `host: '127.0.0.1'` change is intentional; if you later need
|
|
||||||
LAN access to the dev server, set it back to `true` and use the matching URL.
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 10 KiB |
|
|
@ -2,16 +2,6 @@ import type { ReactNode } from 'react';
|
||||||
|
|
||||||
export type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
export type BadgeTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
||||||
|
|
||||||
export function Badge({
|
export function Badge({ tone = 'neutral', children }: { tone?: BadgeTone; children: ReactNode }) {
|
||||||
tone = 'neutral',
|
return <span className={`badge badge-${tone}`}>{children}</span>;
|
||||||
className,
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
tone?: BadgeTone;
|
|
||||||
className?: string;
|
|
||||||
children: ReactNode;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<span className={`badge badge-${tone}${className ? ` ${className}` : ''}`}>{children}</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { Alert } from '../components/Alert';
|
import { Alert } from '../components/Alert';
|
||||||
import { Avatar } from '../components/Avatar';
|
import { Avatar } from '../components/Avatar';
|
||||||
import { Badge } from '../components/Badge';
|
import { Badge } from '../components/Badge';
|
||||||
|
|
@ -6,27 +6,67 @@ import { Button } from '../components/Button';
|
||||||
import { CopyButton } from '../components/CopyButton';
|
import { CopyButton } from '../components/CopyButton';
|
||||||
import { EmptyState } from '../components/EmptyState';
|
import { EmptyState } from '../components/EmptyState';
|
||||||
import { Icon } from '../components/Icon';
|
import { Icon } from '../components/Icon';
|
||||||
|
import { Spinner } from '../components/Spinner';
|
||||||
import { shortenNpub } from '../lib/format';
|
import { shortenNpub } from '../lib/format';
|
||||||
import type { Screen } from '../lib/navigation';
|
import type { Screen } from '../lib/navigation';
|
||||||
import { useApp } from '../state/AppProvider';
|
import { useApp } from '../state/AppProvider';
|
||||||
|
|
||||||
|
type RelayStatus = 'checking' | 'connected' | 'failed';
|
||||||
|
|
||||||
interface HomeScreenProps {
|
interface HomeScreenProps {
|
||||||
onNavigate: (screen: Screen) => void;
|
onNavigate: (screen: Screen) => void;
|
||||||
onCreateProfile: () => void;
|
onCreateProfile: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
||||||
const { state, lastPublish, selectProfile } = useApp();
|
const { state, relayTest, lastPublish } = useApp();
|
||||||
const [selecting, setSelecting] = useState<string | null>(null);
|
const [statuses, setStatuses] = useState<Record<string, { state: RelayStatus; detail?: string }>>(
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
const [testing, setTesting] = useState(false);
|
||||||
|
|
||||||
const onSelect = async (npub: string) => {
|
const enabled = useMemo(
|
||||||
setSelecting(npub);
|
() => state?.settings.relays.filter((r) => r.enabled) ?? [],
|
||||||
try {
|
[state?.settings.relays],
|
||||||
await selectProfile(npub);
|
);
|
||||||
} finally {
|
|
||||||
setSelecting(null);
|
const runCheck = useCallback(async () => {
|
||||||
|
setTesting(true);
|
||||||
|
const entries: Record<string, { state: RelayStatus; detail?: string }> = {};
|
||||||
|
for (const relay of enabled) {
|
||||||
|
entries[relay.url] = { state: 'checking' };
|
||||||
}
|
}
|
||||||
|
setStatuses({ ...entries });
|
||||||
|
await Promise.all(
|
||||||
|
enabled.map(async (relay) => {
|
||||||
|
try {
|
||||||
|
const result = await relayTest(relay.url);
|
||||||
|
entries[relay.url] = {
|
||||||
|
state: 'connected',
|
||||||
|
detail: result.latency_ms != null ? `${result.latency_ms} ms` : 'connected',
|
||||||
};
|
};
|
||||||
|
} catch (error) {
|
||||||
|
entries[relay.url] = {
|
||||||
|
state: 'failed',
|
||||||
|
detail: error instanceof Error ? error.message : String(error),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
setStatuses({ ...entries });
|
||||||
|
setTesting(false);
|
||||||
|
}, [enabled, relayTest]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (enabled.length > 0) {
|
||||||
|
void runCheck();
|
||||||
|
} else {
|
||||||
|
setStatuses({});
|
||||||
|
}
|
||||||
|
}, [enabled, runCheck]);
|
||||||
|
|
||||||
|
const connectedCount = Object.values(statuses).filter((s) => s.state === 'connected').length;
|
||||||
|
const failedCount = Object.values(statuses).filter((s) => s.state === 'failed').length;
|
||||||
|
|
||||||
const active = state?.active_profile ?? null;
|
const active = state?.active_profile ?? null;
|
||||||
const shorten = state?.settings.shorten_npub ?? true;
|
const shorten = state?.settings.shorten_npub ?? true;
|
||||||
|
|
@ -79,72 +119,94 @@ export function HomeScreen({ onNavigate, onCreateProfile }: HomeScreenProps) {
|
||||||
<div className="home-grid">
|
<div className="home-grid">
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<header className="card-header">
|
<header className="card-header">
|
||||||
<h2>Your profiles</h2>
|
<h2>Active profile</h2>
|
||||||
|
</header>
|
||||||
|
<div className="card-body">
|
||||||
|
{active ? (
|
||||||
|
<div className="active-profile-row">
|
||||||
|
<Avatar npub={active.npub} label={active.label} size="lg" />
|
||||||
|
<div className="active-profile-meta">
|
||||||
|
<span className="profile-name">{active.label}</span>
|
||||||
|
<code className="mono" title={active.npub}>
|
||||||
|
{shortenNpub(active.npub, shorten)}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<CopyButton text={active.npub} label="full npub" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p className="muted">
|
||||||
|
No profile selected.{' '}
|
||||||
|
<button type="button" className="linklike" onClick={() => onNavigate('profiles')}>
|
||||||
|
Choose a profile
|
||||||
|
</button>{' '}
|
||||||
|
to get started.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="card">
|
||||||
|
<header className="card-header">
|
||||||
|
<h2>Relays</h2>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={() => onNavigate('profiles')}
|
onClick={() => void runCheck()}
|
||||||
aria-label="Manage profiles"
|
loading={testing}
|
||||||
|
disabled={enabled.length === 0}
|
||||||
>
|
>
|
||||||
<Icon name="users" size={16} />
|
<Icon name="refresh" size={16} />
|
||||||
Manage
|
Refresh
|
||||||
</Button>
|
</Button>
|
||||||
</header>
|
</header>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<ul className="home-profile-list">
|
{enabled.length === 0 ? (
|
||||||
{state?.profiles.map((profile) => (
|
<p className="muted">
|
||||||
<li
|
No relays enabled.{' '}
|
||||||
key={profile.npub}
|
<button type="button" className="linklike" onClick={() => onNavigate('relays')}>
|
||||||
className={`home-profile-row${profile.is_active ? ' is-active' : ''}`}
|
Enable a relay
|
||||||
>
|
</button>{' '}
|
||||||
<Avatar
|
to publish notes.
|
||||||
npub={profile.npub}
|
</p>
|
||||||
label={profile.label}
|
) : testing && Object.keys(statuses).length === 0 ? (
|
||||||
size="lg"
|
<Spinner label="Testing connections…" />
|
||||||
picture={profile.picture}
|
|
||||||
/>
|
|
||||||
<div className="active-profile-meta">
|
|
||||||
<span className="profile-name">
|
|
||||||
{profile.label}
|
|
||||||
{profile.is_active && (
|
|
||||||
<Badge tone="success" className="home-active-badge">
|
|
||||||
Active
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<code className="mono" title={profile.npub}>
|
|
||||||
{shortenNpub(profile.npub, shorten)}
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
<div className="home-profile-actions">
|
|
||||||
<CopyButton text={profile.npub} label="full npub" />
|
|
||||||
{profile.is_active ? (
|
|
||||||
<Button variant="secondary" size="sm" disabled>
|
|
||||||
Selected
|
|
||||||
</Button>
|
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<ul className="relay-status-list">
|
||||||
variant="secondary"
|
{enabled.map((relay) => {
|
||||||
size="sm"
|
const status = statuses[relay.url];
|
||||||
loading={selecting === profile.npub}
|
return (
|
||||||
onClick={() => void onSelect(profile.npub)}
|
<li key={relay.url} className="relay-status-row">
|
||||||
>
|
<span
|
||||||
Select
|
className={`status-dot ${
|
||||||
</Button>
|
status?.state === 'connected'
|
||||||
)}
|
? 'is-ok'
|
||||||
</div>
|
: status?.state === 'failed'
|
||||||
|
? 'is-bad'
|
||||||
|
: 'is-pending'
|
||||||
|
}`}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
<span className="mono relay-url">{relay.url}</span>
|
||||||
|
<span className="relay-status-text">
|
||||||
|
{status?.state === 'connected'
|
||||||
|
? `Connected${status.detail ? ` · ${status.detail}` : ''}`
|
||||||
|
: status?.state === 'failed'
|
||||||
|
? 'Unavailable'
|
||||||
|
: 'Checking…'}
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
<Button
|
)}
|
||||||
variant="primary"
|
{failedCount > 0 &&
|
||||||
size="sm"
|
!testing &&
|
||||||
onClick={onCreateProfile}
|
enabled.length > 0 &&
|
||||||
className="home-add-profile"
|
Object.keys(statuses).length === enabled.length && (
|
||||||
>
|
<p className="muted small">
|
||||||
<Icon name="plus" size={16} />
|
{connectedCount} of {enabled.length} enabled relays reachable.
|
||||||
Add profile
|
</p>
|
||||||
</Button>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1003,10 +1003,16 @@ select {
|
||||||
|
|
||||||
.home-grid {
|
.home-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.home-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.active-profile-row {
|
.active-profile-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -1061,50 +1067,6 @@ select {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home-profile-list {
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-profile-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 14px;
|
|
||||||
padding: 8px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-profile-row.is-active {
|
|
||||||
background: var(--token-item-bg, rgba(0, 0, 0, 0.04));
|
|
||||||
border-color: var(--token-border, rgba(0, 0, 0, 0.12));
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-profile-row .active-profile-meta {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-profile-actions {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-active-badge {
|
|
||||||
margin-left: 8px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.home-add-profile {
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.relay-status-list {
|
.relay-status-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { screen, waitFor, within } from '@testing-library/react';
|
import { screen, waitFor } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { HomeScreen } from '../screens/HomeScreen';
|
import { HomeScreen } from '../screens/HomeScreen';
|
||||||
import { renderWithApp } from './render';
|
import { renderWithApp } from './render';
|
||||||
|
|
@ -36,8 +36,8 @@ describe('HomeScreen', () => {
|
||||||
renderHome(backend);
|
renderHome(backend);
|
||||||
renderWithApp(<HomeScreen onNavigate={vi.fn()} onCreateProfile={vi.fn()} />);
|
renderWithApp(<HomeScreen onNavigate={vi.fn()} onCreateProfile={vi.fn()} />);
|
||||||
|
|
||||||
const aliceRow = (await screen.findByText('Alice')).closest('.home-profile-row') as HTMLElement;
|
await screen.findByText('Alice');
|
||||||
await userEvent.setup().click(within(aliceRow).getByRole('button', { name: 'Copy full npub' }));
|
await userEvent.setup().click(screen.getByRole('button', { name: 'Copy full npub' }));
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(backend.copied).toContain(ALICE);
|
expect(backend.copied).toContain(ALICE);
|
||||||
});
|
});
|
||||||
|
|
@ -54,4 +54,13 @@ describe('HomeScreen', () => {
|
||||||
.click(screen.getByRole('button', { name: /Create your first profile/i }));
|
.click(screen.getByRole('button', { name: /Create your first profile/i }));
|
||||||
expect(onCreateProfile).toHaveBeenCalled();
|
expect(onCreateProfile).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('shows live relay connection status from the backend', async () => {
|
||||||
|
const backend = createFakeBackend();
|
||||||
|
renderHome(backend);
|
||||||
|
renderWithApp(<HomeScreen onNavigate={vi.fn()} onCreateProfile={vi.fn()} />);
|
||||||
|
|
||||||
|
expect(await screen.findAllByText(/Connected/)).not.toHaveLength(0);
|
||||||
|
expect(screen.getAllByText('wss://relay.damus.io')).not.toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import type { UserConfig } from 'vite';
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
host: '127.0.0.1',
|
|
||||||
port: 5173,
|
port: 5173,
|
||||||
strictPort: true,
|
strictPort: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue