diff --git a/docs/PLAN.md b/docs/PLAN.md index f28c3ad..b5fb4c9 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -35,3 +35,4 @@ Updated: 2026-04-02 19. Added service-removal confirmation with linked-user warnings, backend cascade deletion for removed services, and migration that strips persisted legacy `admin` services from stored state. 20. Made `npm run dev` start both the Vite client and Express backend, added a Vite API proxy for local development, and restored `system` as the default panel theme so the login screen follows OS appearance. 21. Re-separated the Settings tab into distinct panel-settings and services cards so panel preferences no longer appear inside the Services section. +22. Restored editable proxy endpoint in panel settings so copied proxy URLs and displayed user endpoints can be corrected from the UI. diff --git a/docs/PROJECT_INDEX.md b/docs/PROJECT_INDEX.md index 7587813..da5055c 100644 --- a/docs/PROJECT_INDEX.md +++ b/docs/PROJECT_INDEX.md @@ -24,7 +24,7 @@ Updated: 2026-04-02 - `src/main.tsx`: application bootstrap - `src/App.tsx`: authenticated panel shell with API-backed login, `sessionStorage` token persistence, localized labels, early theme application, and protected panel mutations -- `src/SystemTab.tsx`: Settings tab with separate panel-settings and services cards, unified service type editing, remove confirmation, and generated config preview +- `src/SystemTab.tsx`: Settings tab with separate panel-settings and services cards, editable proxy endpoint, unified service type editing, remove confirmation, and generated config preview - `src/App.test.tsx`: login-gate, preferences persistence, modal interaction, pause/resume, delete-confirm, and settings-save UI tests - `src/app.css`: full panel styling - `src/data/mockDashboard.ts`: default panel state and frontend fallback snapshot diff --git a/src/App.test.tsx b/src/App.test.tsx index ceca9d9..77089ca 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -142,7 +142,7 @@ describe('App login gate', () => { expect(screen.queryByRole('dialog', { name: /delete user/i })).not.toBeInTheDocument(); }); - it('uses a combined service type field in settings and applies saved ports to the local fallback state', async () => { + it('uses a combined service type field in settings and applies saved proxy endpoint values to the local fallback state', async () => { const user = userEvent.setup(); render(); @@ -151,12 +151,15 @@ describe('App login gate', () => { expect(screen.getByRole('heading', { name: /panel settings/i })).toBeInTheDocument(); expect(screen.getByRole('heading', { name: /^services$/i })).toBeInTheDocument(); - expect(screen.queryByLabelText(/public host/i)).not.toBeInTheDocument(); + expect(screen.getByLabelText(/proxy endpoint/i)).toBeInTheDocument(); expect(screen.queryByLabelText(/command/i)).not.toBeInTheDocument(); expect(screen.queryByLabelText(/protocol/i)).not.toBeInTheDocument(); expect(screen.getAllByLabelText(/type/i)).toHaveLength(3); expect(screen.queryByRole('option', { name: /admin/i })).not.toBeInTheDocument(); + await user.clear(screen.getByLabelText(/proxy endpoint/i)); + await user.type(screen.getByLabelText(/proxy endpoint/i), 'gw.example.net'); + const firstPortInput = screen.getAllByLabelText(/port/i)[0]; await user.clear(firstPortInput); await user.type(firstPortInput, '1180'); @@ -164,7 +167,7 @@ describe('App login gate', () => { await user.click(screen.getByRole('button', { name: /save settings/i })); await user.click(screen.getByRole('button', { name: /users/i })); - expect(screen.getAllByText(/edge\.example\.net:1180/i).length).toBeGreaterThan(0); + expect(screen.getAllByText(/gw\.example\.net:1180/i).length).toBeGreaterThan(0); }); it('warns before deleting a service and removes linked users after confirmation', async () => { diff --git a/src/SystemTab.tsx b/src/SystemTab.tsx index f476106..77ee063 100644 --- a/src/SystemTab.tsx +++ b/src/SystemTab.tsx @@ -75,7 +75,19 @@ export default function SystemTab({

{text.settings.panelTitle}

-
+
+