fix(security): a dismissed status announcement no longer hides the security nudge (#307)
CI / Build & Quality Checks (pull_request) Successful in 3m18s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m21s
CI / Build & Quality Checks (pull_request) Successful in 3m18s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 16m21s
SecurityBanner asked pickBanner whether another strip would show without the dismissed set, so a dismissed Kuma announcement (often pinned for weeks) still counted and suppressed the verify / backup nudge on every device that had dismissed it. The dismissed set is now a shared jotai atom (still persisted to localStorage) used by both banners. Adds a Playwright regression. Fixes #307 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
3878a85339
commit
8e7127a350
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import { MatrixClient, SyncState } from 'matrix-js-sdk';
|
||||
import { Box, Button, config, Icon, IconButton, Icons, IconSrc, Line, Text } from 'folds';
|
||||
import { ContainerColor } from '../../styles/ContainerColor.css';
|
||||
@@ -7,21 +7,9 @@ import { useClientConfig } from '../../hooks/useClientConfig';
|
||||
import { useSyncState } from '../../hooks/useSyncState';
|
||||
import { useServerStatus } from '../../hooks/useServerStatus';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
import { serverStatusAtom } from '../../state/serverStatus';
|
||||
import { serverStatusAtom, statusDismissedAtom } from '../../state/serverStatus';
|
||||
import { pickBanner, resolveStatusPage, StatusBanner } from '../../utils/kumaStatus';
|
||||
|
||||
const DISMISS_KEY = 'lotus-status-banner-dismissed';
|
||||
const DISMISS_MAX = 50;
|
||||
|
||||
const readDismissed = (): string[] => {
|
||||
try {
|
||||
const v = JSON.parse(localStorage.getItem(DISMISS_KEY) ?? '[]');
|
||||
return Array.isArray(v) ? v.filter((k): k is string => typeof k === 'string') : [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const bannerIcon = (b: StripContent): IconSrc => {
|
||||
if (b.kind === 'maintenance') return Icons.Setting;
|
||||
if (b.tone === 'Primary') return Icons.Info;
|
||||
@@ -173,22 +161,14 @@ export function ServerStatusFeature({ mx }: { mx: MatrixClient }) {
|
||||
/** The logged-in app's status strip. */
|
||||
export function ServerStatusBanner() {
|
||||
const { status, syncLost } = useAtomValue(serverStatusAtom);
|
||||
const [dismissed, setDismissed] = useState(readDismissed);
|
||||
const [dismissed, dismissKey] = useAtom(statusDismissedAtom);
|
||||
const banner = pickBanner(status, {
|
||||
syncLost,
|
||||
where: 'client',
|
||||
dismissed: new Set(dismissed),
|
||||
});
|
||||
if (!banner) return null;
|
||||
const dismiss = () => {
|
||||
const next = [...dismissed.filter((k) => k !== banner.key), banner.key].slice(-DISMISS_MAX);
|
||||
try {
|
||||
localStorage.setItem(DISMISS_KEY, JSON.stringify(next));
|
||||
} catch {
|
||||
// storage unavailable — dismissed for this session only
|
||||
}
|
||||
setDismissed(next);
|
||||
};
|
||||
const dismiss = () => dismissKey(banner.key);
|
||||
return <StatusStrip banner={banner} onDismiss={dismiss} />;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user