mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 10:35:51 +00:00
Promote relay public rollout posture
This commit is contained in:
@@ -61,7 +61,7 @@ Power-user shortcuts:
|
||||
- **Secure by Design**: Credentials encrypted at rest, strict API scoping, agent commands disabled by default
|
||||
- **One-Click Updates**: Easy upgrades for supported deployments
|
||||
- **OIDC/SSO/SAML**: Single sign-on with multi-provider support
|
||||
- **Mobile Remote Access (Coming Soon)**: Relay protocol with end-to-end encryption is available now; public mobile app launch is in staged rollout (Relay and above)
|
||||
- **Mobile Remote Access**: Relay protocol with end-to-end encryption for supported Pulse Mobile clients (Relay and above)
|
||||
- **Privacy Focused**: Anonymous telemetry is enabled by default and [fully documented](docs/PRIVACY.md) — no hostnames, credentials, or personal data is ever sent. Disable any time in Settings or via `PULSE_TELEMETRY=false`.
|
||||
|
||||
## ⚡ Quick Start
|
||||
|
||||
+1
-1
@@ -1113,7 +1113,7 @@ TrueNAS resources (pools, datasets, disks, ZFS snapshots, replication tasks, ale
|
||||
|
||||
End-to-end encrypted relay protocol for mobile connectivity.
|
||||
|
||||
> Mobile app status: public rollout is coming soon; current pairing endpoints are primarily used for staged beta onboarding.
|
||||
> Relay pairing endpoints generate the QR code and deep link used by supported Pulse Mobile clients.
|
||||
|
||||
### Relay Configuration (Admin, Relay and Above)
|
||||
- `GET /api/settings/relay` (admin, `settings:read`, Relay+) — Get current relay configuration.
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ Pulse Cloud is the hosted version of Pulse — a fully managed monitoring instan
|
||||
|
||||
1. **Sign up** at the Pulse Cloud portal.
|
||||
2. **Connect your agents** — install the Pulse agent on your infrastructure pointing to your cloud URL.
|
||||
3. **Monitor** — access your dashboard from any browser; mobile app rollout is coming soon.
|
||||
3. **Monitor** — access your dashboard from any browser or supported Pulse Mobile client.
|
||||
|
||||
Each Cloud account gets a dedicated, isolated Pulse instance with its own subdomain (e.g., `yourname.cloud.pulserelay.pro`).
|
||||
|
||||
@@ -21,7 +21,7 @@ Pulse Cloud includes everything in the **Pro** plan, plus:
|
||||
| **Automatic backups** | Daily encrypted backups with 7-day retention |
|
||||
| **Dedicated instance** | Your data runs in an isolated container — not shared with other tenants |
|
||||
| **Wildcard TLS** | HTTPS with auto-renewing certificates |
|
||||
| **Mobile ready** | Relay is pre-configured now; mobile app rollout is coming soon |
|
||||
| **Mobile ready** | Relay is pre-configured for secure Pulse Mobile remote access |
|
||||
|
||||
### Cloud Enterprise (Add-On)
|
||||
|
||||
|
||||
@@ -494,13 +494,13 @@ TrueNAS connections are stored encrypted in `truenas.enc`.
|
||||
|
||||
The relay protocol provides end-to-end encrypted remote access foundations for Pulse mobile connectivity.
|
||||
|
||||
> Mobile app availability: staged rollout (coming soon). Relay configuration is available now for early-access/beta onboarding and future readiness.
|
||||
> Supported Pulse Mobile clients pair here using the generated QR code or deep link once relay is enabled for this instance.
|
||||
|
||||
### Configuration
|
||||
|
||||
1. Go to **Settings → Relay**.
|
||||
2. Toggle relay **On**.
|
||||
3. Use the **QR Code** or **Deep Link** when your mobile beta access is enabled.
|
||||
3. Use the **QR Code** or **Deep Link** to pair a supported Pulse Mobile client.
|
||||
|
||||
### Environment Overrides
|
||||
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ All other documents are supporting references unless explicitly required for evi
|
||||
- **[Unified Resource Model](UNIFIED_RESOURCES.md)** – How all platforms merge into one model with task-based navigation.
|
||||
- **[Unified Navigation Migration](MIGRATION_UNIFIED_NAV.md)** – Upgrading from platform-specific tabs to v6 navigation.
|
||||
- **[TrueNAS Integration](TRUENAS.md)** – First-class TrueNAS SCALE/CORE monitoring (pools, datasets, disks, snapshots, replication).
|
||||
- **[Relay / Mobile Remote Access](RELAY.md)** – End-to-end encrypted relay (mobile app public rollout is coming soon; Relay and above).
|
||||
- **[Relay / Mobile Remote Access](RELAY.md)** – End-to-end encrypted relay for supported Pulse Mobile clients (Relay and above).
|
||||
- **[Recovery Central](RECOVERY.md)** – Unified backup, snapshot, and replication view across all providers.
|
||||
- **[Pulse Cloud (Hosted)](CLOUD.md)** – Fully managed hosting with automatic updates and backups.
|
||||
- **[Pulse AI](AI.md)** – Chat assistant, patrol findings, alert analysis, intelligence, and forecasts.
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
Pulse Relay provides **end-to-end encrypted remote access** foundations for Pulse instances. It allows secure remote connectivity without exposing your Pulse server to the public internet.
|
||||
|
||||
> Mobile app status: public rollout is coming soon. Relay remains available now for early-access/beta onboarding.
|
||||
> Supported Pulse Mobile clients pair from **Settings → Relay** using a QR code or deep link and connect through Pulse Relay over end-to-end encrypted remote access.
|
||||
|
||||
## How It Works
|
||||
|
||||
@@ -22,7 +22,7 @@ Pulse Relay provides **end-to-end encrypted remote access** foundations for Puls
|
||||
|
||||
1. Go to **Settings → Relay**.
|
||||
2. Toggle relay **On**.
|
||||
3. Use the **QR Code** or **Deep Link** when mobile beta access is enabled.
|
||||
3. Use the **QR Code** or **Deep Link** to pair a supported Pulse Mobile client.
|
||||
4. Your paired mobile client connects through relay.
|
||||
|
||||
## Requirements
|
||||
|
||||
@@ -1982,15 +1982,11 @@
|
||||
"status": "partial",
|
||||
"completion": {
|
||||
"state": "bounded-residual",
|
||||
"summary": "Relay infrastructure is at the RC floor; the remaining residual is explicitly limited to the backend-owned mobile relay capability boundary and the later public rollout posture required for GA promotion.",
|
||||
"summary": "Relay infrastructure is at the RC floor; the remaining residual is limited to the backend-owned mobile relay capability boundary.",
|
||||
"tracking": [
|
||||
{
|
||||
"kind": "lane-followup",
|
||||
"id": "relay-mobile-capability-boundary"
|
||||
},
|
||||
{
|
||||
"kind": "lane-followup",
|
||||
"id": "relay-public-rollout-posture"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -3155,19 +3151,6 @@
|
||||
"subsystem_ids": [
|
||||
"relay-runtime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "relay-public-rollout-posture",
|
||||
"summary": "Replace the current early-access and coming-soon relay public posture with an explicit public rollout decision only after mobile availability, onboarding language, and support expectations are intentionally promoted for normal use.",
|
||||
"owner": "project-owner",
|
||||
"status": "planned",
|
||||
"recorded_at": "2026-03-28",
|
||||
"lane_ids": [
|
||||
"L7"
|
||||
],
|
||||
"subsystem_ids": [
|
||||
"relay-runtime"
|
||||
]
|
||||
}
|
||||
],
|
||||
"coverage_gaps": [
|
||||
|
||||
@@ -803,12 +803,17 @@ provisioning must complete under an explicit background timeout instead of
|
||||
depending on the inbound Stripe request context surviving long enough for first
|
||||
boot and health polling.
|
||||
That same paid relay onboarding boundary now also owns QR-token lifecycle on
|
||||
the staged mobile rollout surface. `RelaySettingsPanel.tsx`,
|
||||
the supported Pulse Mobile pairing surface. `RelaySettingsPanel.tsx`,
|
||||
`RelayPairingSection.tsx`, and `useRelaySettingsPanelState.ts` may revoke a
|
||||
displayed pairing token only when canonical token metadata still shows no
|
||||
`lastUsedAt`; once a token has been used by a paired device, refreshing or
|
||||
hiding the QR must preserve that credential instead of treating it as
|
||||
disposable UI state.
|
||||
That same paid relay onboarding boundary also owns the operator-facing rollout
|
||||
posture on the licensed settings surface: relay paywall and pairing copy must
|
||||
describe supported Pulse Mobile pairing as a normal-use Relay capability, and
|
||||
must not fall back to staged-beta or coming-soon messaging once the owned
|
||||
pairing/runtime path is live.
|
||||
The customer-account surface is now also an explicit cloud-paid ownership
|
||||
boundary. Pulse already has a real hosted control-plane portal in
|
||||
`internal/cloudcp/portal/`, account/workspace mutation APIs in
|
||||
|
||||
@@ -206,6 +206,11 @@ work extends shared components instead of creating new local variants.
|
||||
the governed dashboard empty state route first-time operators into
|
||||
Infrastructure Install, instead of preserving a separate root-only jump to
|
||||
`/infrastructure` that drifts from the rest of the onboarding contract.
|
||||
12. Keep relay settings shell copy on the shared presentation owner in
|
||||
`frontend-modern/src/utils/relayPresentation.ts`. The route metadata in
|
||||
`settingsHeaderMeta.ts` and the leading `SettingsPanel` in
|
||||
`RelaySettingsPanel.tsx` must reuse the same description and availability
|
||||
copy instead of drifting into separate rollout or pairing wording.
|
||||
|
||||
## Current State
|
||||
|
||||
@@ -1412,6 +1417,12 @@ That shared shell boundary now also covers version-matched docs-link framing:
|
||||
customer-facing privacy disclosures in shared settings surfaces must route
|
||||
through `frontend-modern/src/utils/docsLinks.ts` rather than panel-local
|
||||
external URLs.
|
||||
The same shell boundary now also owns shared relay route framing copy:
|
||||
`frontend-modern/src/utils/relayPresentation.ts` is the canonical owner for
|
||||
the top-level relay settings description and availability copy used by both
|
||||
`settingsHeaderMeta.ts` and `RelaySettingsPanel.tsx`, so the route shell and
|
||||
its first `SettingsPanel` cannot drift into separate rollout or pairing
|
||||
descriptions.
|
||||
|
||||
Single-surface settings pages that only render one canonical `SettingsPanel`
|
||||
must stay rooted directly at that panel instead of wrapping it in an extra
|
||||
|
||||
@@ -70,7 +70,7 @@ All other documents are supporting references unless explicitly required for evi
|
||||
- **[Unified Resource Model](UNIFIED_RESOURCES.md)** – How all platforms merge into one model with task-based navigation.
|
||||
- **[Unified Navigation Migration](MIGRATION_UNIFIED_NAV.md)** – Upgrading from platform-specific tabs to v6 navigation.
|
||||
- **[TrueNAS Integration](TRUENAS.md)** – First-class TrueNAS SCALE/CORE monitoring (pools, datasets, disks, snapshots, replication).
|
||||
- **[Relay / Mobile Remote Access](RELAY.md)** – End-to-end encrypted relay (mobile app public rollout is coming soon; Relay and above).
|
||||
- **[Relay / Mobile Remote Access](RELAY.md)** – End-to-end encrypted relay for supported Pulse Mobile clients (Relay and above).
|
||||
- **[Recovery Central](RECOVERY.md)** – Unified backup, snapshot, and replication view across all providers.
|
||||
- **[Pulse Cloud (Hosted)](CLOUD.md)** – Fully managed hosting with automatic updates and backups.
|
||||
- **[Pulse AI](AI.md)** – Chat assistant, patrol findings, alert analysis, intelligence, and forecasts.
|
||||
|
||||
@@ -8,13 +8,18 @@ import { formField, labelClass, controlClass, formHelpText } from '@/components/
|
||||
import { trackUpgradeClicked } from '@/utils/upgradeMetrics';
|
||||
import { getSettingsConfigurationLoadingState } from '@/utils/settingsShellPresentation';
|
||||
import {
|
||||
RELAY_BETA_MESSAGE_CLASS,
|
||||
RELAY_BETA_TITLE_CLASS,
|
||||
RELAY_ENABLE_HELP_TEXT,
|
||||
RELAY_INFO_MESSAGE_CLASS,
|
||||
RELAY_INFO_TITLE_CLASS,
|
||||
RELAY_INLINE_ACTION_CLASS,
|
||||
RELAY_LAST_ERROR_CLASS,
|
||||
RELAY_LICENSE_REQUIRED_MESSAGE,
|
||||
RELAY_PAIRING_AVAILABILITY_MESSAGE,
|
||||
RELAY_PAIRING_AVAILABILITY_TITLE,
|
||||
RELAY_PRIMARY_BUTTON_CLASS,
|
||||
RELAY_PRIMARY_LINK_CLASS,
|
||||
RELAY_READONLY_NOTICE_CLASS,
|
||||
RELAY_SETTINGS_DESCRIPTION,
|
||||
} from '@/utils/relayPresentation';
|
||||
import { UPGRADE_TRIAL_LABEL } from '@/utils/upgradePresentation';
|
||||
import { RelayPairingSection } from './RelayPairingSection';
|
||||
@@ -31,7 +36,7 @@ export const RelaySettingsPanel: Component<RelaySettingsPanelProps> = (props) =>
|
||||
return (
|
||||
<SettingsPanel
|
||||
title="Remote Access"
|
||||
description="Configure Pulse relay connectivity for secure remote access (mobile rollout coming soon)."
|
||||
description={RELAY_SETTINGS_DESCRIPTION}
|
||||
icon={<RadioTower size={20} strokeWidth={2} />}
|
||||
>
|
||||
<Show when={!state.loading()} fallback={<div class="text-sm ">Loading...</div>}>
|
||||
@@ -41,10 +46,7 @@ export const RelaySettingsPanel: Component<RelaySettingsPanelProps> = (props) =>
|
||||
<RadioTower size={20} class="text-blue-500 mt-0.5 flex-shrink-0" strokeWidth={2} />
|
||||
<div>
|
||||
<p class="text-sm font-medium text-base-content">Remote Access (Relay)</p>
|
||||
<p class="text-sm text-muted mt-1">
|
||||
Remote access via Pulse Relay requires a Relay license or above. Mobile app
|
||||
public rollout is coming soon.
|
||||
</p>
|
||||
<p class="text-sm text-muted mt-1">{RELAY_LICENSE_REQUIRED_MESSAGE}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col sm:flex-row items-center gap-2">
|
||||
@@ -78,7 +80,7 @@ export const RelaySettingsPanel: Component<RelaySettingsPanelProps> = (props) =>
|
||||
return (
|
||||
<SettingsPanel
|
||||
title="Remote Access"
|
||||
description="Configure Pulse relay connectivity for secure remote access (mobile rollout coming soon)."
|
||||
description={RELAY_SETTINGS_DESCRIPTION}
|
||||
icon={<RadioTower size={20} strokeWidth={2} />}
|
||||
>
|
||||
<Show
|
||||
@@ -96,11 +98,8 @@ export const RelaySettingsPanel: Component<RelaySettingsPanelProps> = (props) =>
|
||||
</Show>
|
||||
|
||||
<Card tone="info" padding="md">
|
||||
<p class={RELAY_BETA_TITLE_CLASS}>Pulse Mobile rollout is coming soon</p>
|
||||
<p class={RELAY_BETA_MESSAGE_CLASS}>
|
||||
Relay infrastructure is available now. Pairing and remote sessions are currently
|
||||
intended for staged beta access.
|
||||
</p>
|
||||
<p class={RELAY_INFO_TITLE_CLASS}>{RELAY_PAIRING_AVAILABILITY_TITLE}</p>
|
||||
<p class={RELAY_INFO_MESSAGE_CLASS}>{RELAY_PAIRING_AVAILABILITY_MESSAGE}</p>
|
||||
</Card>
|
||||
|
||||
{/* Connection Status */}
|
||||
@@ -136,10 +135,7 @@ export const RelaySettingsPanel: Component<RelaySettingsPanelProps> = (props) =>
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div>
|
||||
<label class={labelClass()}>Enable Remote Access</label>
|
||||
<p class={formHelpText}>
|
||||
Connect this Pulse instance to the relay server for secure remote access and mobile
|
||||
beta readiness.
|
||||
</p>
|
||||
<p class={formHelpText}>{RELAY_ENABLE_HELP_TEXT}</p>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={state.config()?.enabled ?? false}
|
||||
|
||||
@@ -146,6 +146,23 @@ describe('RelaySettingsPanel runtime', () => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('shows supported Pulse Mobile pairing copy on the relay paywall', async () => {
|
||||
hasFeatureMock.mockReturnValue(false);
|
||||
|
||||
render(() => <RelaySettingsPanel canManage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Remote Access (Relay)')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Remote access via Pulse Relay requires a Relay license or above. Pair supported Pulse Mobile clients with this instance using a QR code or deep link.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByRole('link', { name: 'Upgrade' })).toHaveAttribute('href', '/upgrade');
|
||||
});
|
||||
|
||||
it('loads connected relay state and generates a pairing QR payload', async () => {
|
||||
render(() => <RelaySettingsPanel canManage />);
|
||||
|
||||
@@ -153,6 +170,12 @@ describe('RelaySettingsPanel runtime', () => {
|
||||
expect(screen.getByDisplayValue('wss://relay.example.test/ws/instance')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(screen.getByText('Pair Pulse Mobile through Relay')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Supported Pulse Mobile clients connect to this Pulse instance with a QR code or deep link over end-to-end encrypted relay connectivity.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('Connected')).toBeInTheDocument();
|
||||
expect(screen.getByText('Instance: instance-local')).toBeInTheDocument();
|
||||
expect(screen.getByText('1 active channel')).toBeInTheDocument();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { SELF_HOSTED_PRO_BILLING_PRESENTATION } from '../selfHostedBillingPresentation';
|
||||
import { RELAY_SETTINGS_DESCRIPTION } from '@/utils/relayPresentation';
|
||||
import settingsSource from '../Settings.tsx?raw';
|
||||
import settingsDialogsSource from '../SettingsDialogs.tsx?raw';
|
||||
import settingsShellSource from '../SettingsPageShell.tsx?raw';
|
||||
@@ -1318,6 +1319,13 @@ describe('Settings architecture guardrails', () => {
|
||||
expect(SETTINGS_HEADER_META['organization-billing'].description).toContain('plan limits');
|
||||
});
|
||||
|
||||
it('keeps relay shell copy on the shared relay presentation owner', () => {
|
||||
expect(settingsHeaderMetaSource).toContain('RELAY_SETTINGS_DESCRIPTION');
|
||||
expect(relaySettingsPanelSource).toContain('description={RELAY_SETTINGS_DESCRIPTION}');
|
||||
expect(SETTINGS_HEADER_META['system-relay'].description).toBe(RELAY_SETTINGS_DESCRIPTION);
|
||||
expect(SETTINGS_HEADER_META['system-relay'].description).toContain('Pulse Mobile pairing');
|
||||
});
|
||||
|
||||
it('keeps self-hosted billing shell copy in a settings-owned presentation module', () => {
|
||||
expect(selfHostedBillingPresentationSource).toContain(
|
||||
'export const SELF_HOSTED_PRO_BILLING_PRESENTATION',
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { SettingsHeaderMetaMap } from './settingsNavigationModel';
|
||||
import { SELF_HOSTED_PRO_BILLING_PRESENTATION } from './selfHostedBillingPresentation';
|
||||
import { RELAY_SETTINGS_DESCRIPTION } from '@/utils/relayPresentation';
|
||||
|
||||
export const SETTINGS_HEADER_META: SettingsHeaderMetaMap = {
|
||||
proxmox: {
|
||||
@@ -34,8 +35,7 @@ export const SETTINGS_HEADER_META: SettingsHeaderMetaMap = {
|
||||
},
|
||||
'system-relay': {
|
||||
title: 'Remote Access',
|
||||
description:
|
||||
'Configure Pulse relay connectivity for secure remote access (mobile rollout coming soon).',
|
||||
description: RELAY_SETTINGS_DESCRIPTION,
|
||||
},
|
||||
'system-billing': {
|
||||
title: SELF_HOSTED_PRO_BILLING_PRESENTATION.shellTitle,
|
||||
|
||||
@@ -2,11 +2,13 @@ import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
getRelayConnectionPresentation,
|
||||
getRelayDiagnosticClass,
|
||||
RELAY_BETA_MESSAGE_CLASS,
|
||||
RELAY_BETA_TITLE_CLASS,
|
||||
RELAY_CODE_BLOCK_CLASS,
|
||||
RELAY_ENABLE_HELP_TEXT,
|
||||
RELAY_INFO_MESSAGE_CLASS,
|
||||
RELAY_INFO_TITLE_CLASS,
|
||||
RELAY_INLINE_ACTION_CLASS,
|
||||
RELAY_LAST_ERROR_CLASS,
|
||||
RELAY_LICENSE_REQUIRED_MESSAGE,
|
||||
RELAY_ONBOARDING_DESCRIPTION,
|
||||
RELAY_ONBOARDING_DISCONNECTED_LABEL,
|
||||
RELAY_ONBOARDING_SETUP_LABEL,
|
||||
@@ -16,11 +18,14 @@ import {
|
||||
RELAY_ONBOARDING_SETUP_WIZARD_TRIAL_LABEL,
|
||||
RELAY_ONBOARDING_TRIAL_HINT,
|
||||
RELAY_ONBOARDING_UPGRADE_LABEL,
|
||||
RELAY_PAIRING_AVAILABILITY_MESSAGE,
|
||||
RELAY_PAIRING_AVAILABILITY_TITLE,
|
||||
RELAY_PRIMARY_BUTTON_CLASS,
|
||||
RELAY_PRIMARY_LINK_CLASS,
|
||||
RELAY_QR_IMAGE_CLASS,
|
||||
RELAY_READONLY_NOTICE_CLASS,
|
||||
RELAY_SECONDARY_BUTTON_CLASS,
|
||||
RELAY_SETTINGS_DESCRIPTION,
|
||||
} from '@/utils/relayPresentation';
|
||||
|
||||
describe('relayPresentation', () => {
|
||||
@@ -58,8 +63,8 @@ describe('relayPresentation', () => {
|
||||
expect(RELAY_PRIMARY_LINK_CLASS).toContain('text-center');
|
||||
expect(RELAY_SECONDARY_BUTTON_CLASS).toContain('bg-surface-hover');
|
||||
expect(RELAY_INLINE_ACTION_CLASS).toContain('hover:underline');
|
||||
expect(RELAY_BETA_TITLE_CLASS).toContain('font-medium');
|
||||
expect(RELAY_BETA_MESSAGE_CLASS).toContain('text-muted');
|
||||
expect(RELAY_INFO_TITLE_CLASS).toContain('font-medium');
|
||||
expect(RELAY_INFO_MESSAGE_CLASS).toContain('text-muted');
|
||||
expect(RELAY_LAST_ERROR_CLASS).toContain('text-red-600');
|
||||
expect(RELAY_CODE_BLOCK_CLASS).toContain('font-mono');
|
||||
expect(RELAY_QR_IMAGE_CLASS).toContain('border-border');
|
||||
@@ -67,6 +72,14 @@ describe('relayPresentation', () => {
|
||||
expect(getRelayDiagnosticClass('warning')).toContain('bg-amber-50');
|
||||
});
|
||||
|
||||
it('centralizes relay availability copy', () => {
|
||||
expect(RELAY_SETTINGS_DESCRIPTION).toContain('Pulse Mobile pairing');
|
||||
expect(RELAY_LICENSE_REQUIRED_MESSAGE).toContain('supported Pulse Mobile clients');
|
||||
expect(RELAY_PAIRING_AVAILABILITY_TITLE).toBe('Pair Pulse Mobile through Relay');
|
||||
expect(RELAY_PAIRING_AVAILABILITY_MESSAGE).toContain('QR code or deep link');
|
||||
expect(RELAY_ENABLE_HELP_TEXT).toContain('Pulse Mobile pairing');
|
||||
});
|
||||
|
||||
it('centralizes relay onboarding copy', () => {
|
||||
expect(RELAY_ONBOARDING_TITLE).toBe('Pair Your Mobile Device');
|
||||
expect(RELAY_ONBOARDING_DESCRIPTION).toContain('remote monitoring');
|
||||
|
||||
@@ -17,8 +17,8 @@ export const RELAY_SECONDARY_BUTTON_CLASS =
|
||||
'min-h-10 sm:min-h-10 px-3 py-2 text-sm font-medium text-base-content bg-surface-hover hover:bg-surface-hover rounded-md disabled:opacity-50';
|
||||
export const RELAY_INLINE_ACTION_CLASS =
|
||||
'text-sm text-indigo-500 hover:underline disabled:opacity-50';
|
||||
export const RELAY_BETA_TITLE_CLASS = 'text-sm font-medium text-base-content';
|
||||
export const RELAY_BETA_MESSAGE_CLASS = 'text-xs text-muted mt-1';
|
||||
export const RELAY_INFO_TITLE_CLASS = 'text-sm font-medium text-base-content';
|
||||
export const RELAY_INFO_MESSAGE_CLASS = 'text-xs text-muted mt-1';
|
||||
export const RELAY_LAST_ERROR_CLASS =
|
||||
'mt-2 text-xs text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900 rounded px-2 py-1';
|
||||
export const RELAY_CODE_BLOCK_CLASS =
|
||||
@@ -26,6 +26,15 @@ export const RELAY_CODE_BLOCK_CLASS =
|
||||
export const RELAY_QR_IMAGE_CLASS = 'rounded-md border border-border p-2';
|
||||
export const RELAY_DIAGNOSTICS_WRAP_CLASS = 'space-y-2';
|
||||
export const RELAY_DIAGNOSTICS_TITLE_CLASS = 'text-xs font-semibold text-base-content';
|
||||
export const RELAY_SETTINGS_DESCRIPTION =
|
||||
'Configure Pulse relay connectivity for secure remote access and Pulse Mobile pairing.';
|
||||
export const RELAY_LICENSE_REQUIRED_MESSAGE =
|
||||
'Remote access via Pulse Relay requires a Relay license or above. Pair supported Pulse Mobile clients with this instance using a QR code or deep link.';
|
||||
export const RELAY_PAIRING_AVAILABILITY_TITLE = 'Pair Pulse Mobile through Relay';
|
||||
export const RELAY_PAIRING_AVAILABILITY_MESSAGE =
|
||||
'Supported Pulse Mobile clients connect to this Pulse instance with a QR code or deep link over end-to-end encrypted relay connectivity.';
|
||||
export const RELAY_ENABLE_HELP_TEXT =
|
||||
'Connect this Pulse instance to the relay server for secure remote access and Pulse Mobile pairing.';
|
||||
export const RELAY_ONBOARDING_TITLE = 'Pair Your Mobile Device';
|
||||
export const RELAY_ONBOARDING_DESCRIPTION =
|
||||
'Pulse Relay lets your phone securely connect to this Pulse instance for remote monitoring.';
|
||||
|
||||
@@ -29,7 +29,7 @@ const SETTINGS_SHELL_ROUTES = [
|
||||
{
|
||||
route: '/settings/system-relay',
|
||||
title: 'Remote Access',
|
||||
description: 'Configure Pulse relay connectivity for secure remote access (mobile rollout coming soon).',
|
||||
description: 'Configure Pulse relay connectivity for secure remote access and Pulse Mobile pairing.',
|
||||
},
|
||||
{
|
||||
route: '/settings/security-auth',
|
||||
|
||||
Reference in New Issue
Block a user