Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions frontend/.lint-ceiling.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"total": 132,
"total": 99,
"rules": {
"@typescript-eslint/no-unused-vars": 39,
"@typescript-eslint/no-explicit-any": 26,
"react-hooks/set-state-in-effect": 16,
"react-hooks/static-components": 14,
"@typescript-eslint/no-unused-vars": 27,
"@typescript-eslint/no-explicit-any": 21,
"react-hooks/set-state-in-effect": 13,
"react-hooks/preserve-manual-memoization": 12,
"react-refresh/only-export-components": 12,
"no-irregular-whitespace": 1,
"react-refresh/only-export-components": 10,
"react-hooks/static-components": 6,
"react-hooks/purity": 3,
"prefer-const": 2,
"@typescript-eslint/ban-ts-comment": 1,
Expand Down
2 changes: 1 addition & 1 deletion frontend/e2e/empty-states.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async function assertNoNonZeroMetrics(page: Page, where: string) {
if (!text) continue;
// Strip thousands separators (space, NBSP, narrow NBSP, comma) so "1 200"
// is read as 1200 rather than as 1 and 200.
const digits = text.replace(/[\s  ,]/g, '');
const digits = text.replace(/[\s\u00a0\u202f,]/g, '');

// "N/M" ratios — "0/4 étapes", "0/12 risques chiffrés". Only the numerator
// is tenant data; the denominator is a total (onboarding steps, registered
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/features/onboarding/PersonalizeCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ import { useUIStore, type Theme, type Variant } from '../../store/uiStore';
import { ACCENT_LABELS, ACCENT_PRESETS } from '../../shared/accentPresets';

// Swatch colours only; the list of accents comes from shared/accentPresets.
// The preview tokens in tokens.css (--swatch-*), which mirror each variant's
// real accent per theme. The literals that stood here (#0a84ff, #7c6cff)
// matched neither theme's accent.
const SWATCH: Record<Variant, string> = {
azure: '#0a84ff',
iris: '#7c6cff',
azure: 'var(--swatch-azure)',
iris: 'var(--swatch-iris)',
};
const ACCENTS = ACCENT_PRESETS.map((key) => ({
key,
Expand Down
18 changes: 1 addition & 17 deletions frontend/src/features/settings/SettingsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
// Integrations, Notifications, Security, Billing, Danger. Endpoints whose tables
// aren't migrated yet (roles/tenants/audit) degrade to an honest unavailable state.

import { useEffect, useMemo, useState } from 'react';
import { useEffect, useState } from 'react';
import { useSearchParams, useNavigate, useLocation } from 'react-router';
import { toast } from 'sonner';
import {
Settings as SettingsIcon,
Users,
Expand All @@ -22,13 +21,9 @@ import {
Shield,
CreditCard,
AlertTriangle,
Plus,
FileText,
Check,
Trash2,
Copy,
Database,
PowerOff,
type LucideIcon,
} from 'lucide-react';
import {
Expand All @@ -46,8 +41,6 @@ import { useAuthStore } from '../../hooks/useAuthStore';
import { SessionsPanel } from '../auth/SessionsPanel';
import { ChangePasswordCard } from '../auth/ChangePasswordCard';
import { MembersView } from '../organization/MembersView';
import { relTime } from '../risks/riskMap';
import { api } from '../../lib/api';
import { useCustomFields, useTenants } from './adminData';
import { ApiTokensPanel } from './ApiTokensPanel';
import {
Expand All @@ -57,14 +50,6 @@ import {
import type { NotificationPreferencePatch } from '../notifications/notificationService';
import { useChannelConfig } from '../automation/useAutomation';
import { useVulnIntegrations, useVulnTicketing } from '../vulnerabilities/useVulnIntegrations';
import {
DataTable,
useTableState,
type Column,
type Facet,
type RowAction,
} from '../../shared/datatable';
import { DangerConfirm } from '../../shared/DangerConfirm';
import { PersonalizeCard } from '../onboarding/PersonalizeCard';
import { BillingPanel } from '../billing/BillingPanel';
import { DangerZonePanel } from '../billing/DangerZonePanel';
Expand All @@ -74,7 +59,6 @@ import { OrganizationProfileForm } from './OrganizationProfileForm';
import { OrganizationLogoField } from './OrganizationLogoField';
import { OrgLogo } from '../organization/OrgLogo';
import { ProfileTab } from '../profile/ProfileTab';
import type { LocaleCode } from '../../i18n/locales';
import { useI18n } from '../../hooks/useI18n';
import { localeTag } from '../../i18n/locales';

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/__tests__/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
} from '../format';

/** Intl inserts narrow/non-breaking spaces; compare on the digits and marks. */
const norm = (s: string) => s.replace(/[  ‎‏]/g, ' ');
const norm = (s: string) => s.replace(/[\u00a0\u202f\u200e\u200f]/g, ' ');

describe('locale-aware formatting', () => {
it('groups numbers in the reader’s conventions', () => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/__tests__/translate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const fixture: Partial<Record<'fr' | 'en' | 'ar', Catalog>> = {
},
};

const norm = (s: string) => s.replace(/[  ‎‏]/g, ' ');
const norm = (s: string) => s.replace(/[\u00a0\u202f\u200e\u200f]/g, ' ');

describe('translate', () => {
it('reads a dotted key', () => {
Expand Down
9 changes: 7 additions & 2 deletions frontend/src/shared/useHotkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// while ⌘/Ctrl/Alt are held (those belong to the browser or ⌘K). Shift is allowed
// because `?` is Shift+/. Modal-scoped keys (Esc, ⌘Enter) keep using useKeyboard.

import { useEffect, useRef } from 'react';
import { useEffect, useLayoutEffect, useRef } from 'react';

export interface Hotkey {
/** Single key to match, case-insensitive: 'n', '/', '?', 't', 'g'. */
Expand All @@ -25,8 +25,13 @@ function isTyping(target: EventTarget | null): boolean {

export function useHotkeys(hotkeys: Hotkey[], enabled = true): void {
// Keep the latest handlers without re-binding the listener every render.
// Updated in a layout effect, not during render (react-hooks/refs): it runs
// after every commit and before any later keydown, so the listener never
// sees stale handlers.
const ref = useRef(hotkeys);
ref.current = hotkeys;
useLayoutEffect(() => {
ref.current = hotkeys;
});

useEffect(() => {
if (!enabled) return;
Expand Down
Loading