diff --git a/client/src/api/client.behavior.test.ts b/client/src/api/client.behavior.test.ts index 71837160a..e33de84f8 100644 --- a/client/src/api/client.behavior.test.ts +++ b/client/src/api/client.behavior.test.ts @@ -111,7 +111,7 @@ describe('client > request interceptor', () => { expect(sink[0].headers['X-Idempotency-Key']).toBe('queued-key') }) - it('FE-APIWIRE-004: falls back to a random token when crypto.randomUUID is missing', async () => { + it('FE-APIWIRE-004: falls back to getRandomValues when crypto.randomUUID is missing', async () => { const realCrypto = globalThis.crypto vi.stubGlobal('crypto', { getRandomValues: realCrypto.getRandomValues.bind(realCrypto), @@ -120,9 +120,30 @@ describe('client > request interceptor', () => { const sink: InternalAxiosRequestConfig[] = [] await apiClient.post('/probe', {}, { adapter: okAdapter(sink) }) - const key = String(sink[0].headers['X-Idempotency-Key']) - expect(key).toMatch(/^[a-z0-9]+$/) - expect(key).not.toMatch(/-/) + // randomUUID needs a secure context, so on the plain-http installs the + // README documents this branch is what actually runs. getRandomValues has no + // such requirement, so the fallback is still a full v4 UUID. + expect(String(sink[0].headers['X-Idempotency-Key'])).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/, + ) + }) + + it('FE-APIWIRE-004b: the last-resort key is never degenerate, even with no Web Crypto at all', async () => { + vi.stubGlobal('crypto', undefined) + + const keys = new Set() + for (let i = 0; i < 50; i++) { + const sink: InternalAxiosRequestConfig[] = [] + await apiClient.post('/probe', {}, { adapter: okAdapter(sink) }) + keys.add(String(sink[0].headers['X-Idempotency-Key'])) + } + + // The old fallback was Math.random().toString(36).slice(2), which is not + // length-stable: 0.5 yields a single character and 0 yields the empty string. + // An empty key makes the server skip deduplication entirely, so a retried + // write applies twice. + for (const k of keys) expect(k.length).toBeGreaterThan(16) + expect(keys.size).toBe(50) }) it('FE-APIWIRE-005: the socket id header is omitted while no socket is connected', async () => { diff --git a/client/src/api/client.ts b/client/src/api/client.ts index d3c60819c..4b3887977 100644 --- a/client/src/api/client.ts +++ b/client/src/api/client.ts @@ -1,6 +1,7 @@ import axios, { AxiosInstance } from 'axios' import type { z } from 'zod' import type { Place } from '../types' +import { randomId } from '../utils/randomId' import { weatherResultSchema, type WeatherResult, inAppListResultSchema, type InAppListResult, @@ -151,10 +152,7 @@ apiClient.interceptors.request.use( // The mutation queue sets its own pre-generated key; skip if already set. const method = (config.method ?? '').toLowerCase() if (MUTATING_METHODS.has(method) && !config.headers['X-Idempotency-Key']) { - const key = typeof crypto !== 'undefined' && crypto.randomUUID - ? crypto.randomUUID() - : Math.random().toString(36).slice(2) - config.headers['X-Idempotency-Key'] = key + config.headers['X-Idempotency-Key'] = randomId() } return config }, diff --git a/client/src/components/Admin/AddonManager.tsx b/client/src/components/Admin/AddonManager.tsx index c30e92fb9..7ae90b72e 100644 --- a/client/src/components/Admin/AddonManager.tsx +++ b/client/src/components/Admin/AddonManager.tsx @@ -196,7 +196,7 @@ export default function AddonManager({ bagTrackingEnabled, onToggleBagTracking, {bagTrackingEnabled ? t('admin.addons.enabled') : t('admin.addons.disabled')} - @@ -470,7 +470,7 @@ function LlmParsingConfig({ addon }: { addon: Addon }) { {installed.length > 0 && (
{installed.map(name => ( -
{installedHere ? ( - ) : ( - )} @@ -526,7 +526,7 @@ function LlmParsingConfig({ addon }: { addon: Addon }) { )} - @@ -589,7 +589,7 @@ function AddonRow({ addon, onToggle, t, nameOverride, descriptionOverride, statu {isComingSoon ? t('admin.addons.disabled') : enabledState ? t('admin.addons.enabled') : t('admin.addons.disabled')} {!hideToggle && ( - )} {expanded && hidden > 0 && ( - @@ -146,7 +146,7 @@ export default function AdminMcpTokensPanel() { {new Date(session.created_at).toLocaleDateString(locale)} - - @@ -240,11 +240,11 @@ export default function AdminMcpTokensPanel() {

{t('admin.mcpTokens.deleteTitle')}

{t('admin.mcpTokens.deleteMessage')}

- - diff --git a/client/src/components/Admin/AdminPluginsPanel.tsx b/client/src/components/Admin/AdminPluginsPanel.tsx index 4ca8ae1f1..b0c468d65 100644 --- a/client/src/components/Admin/AdminPluginsPanel.tsx +++ b/client/src/components/Admin/AdminPluginsPanel.tsx @@ -187,7 +187,7 @@ const PERM_KEYS = PLUGIN_PERMISSIONS const KNOWN_TYPES = ['widget', 'page', 'integration', 'trip-page'] function isNewer(a: string, b: string): boolean { - const nums = (v: string) => v.split('-')[0].split('.').map(n => parseInt(n, 10) || 0) + const nums = (v: string) => v.split('-')[0].split('.').map(n => Number.parseInt(n, 10) || 0) const pa = nums(a), pb = nums(b) for (let i = 0; i < 3; i++) { const x = pa[i] || 0, y = pb[i] || 0 @@ -795,11 +795,11 @@ export default function AdminPluginsPanel() {
- - @@ -842,11 +842,11 @@ export default function AdminPluginsPanel() { valueLabel={sortLabel(sort, t)} onPick={v => setSort(v as SortKey)} /> - - @@ -871,7 +871,7 @@ export default function AdminPluginsPanel() {
{t('admin.plugins.updatesAvailable', { count: updatable.length })} - @@ -913,7 +913,7 @@ export default function AdminPluginsPanel() {
e.stopPropagation()}>
{errorsFor.id} — {t('admin.plugins.errorLog')} - +
{errorsFor.rows.length === 0 ?

{t('admin.plugins.noErrors')}

: @@ -935,7 +935,7 @@ export default function AdminPluginsPanel() {
e.stopPropagation()}>
{egressFor.id} — {t('admin.plugins.allowedHosts')} - +
{!egressFor.supported ? ( @@ -949,7 +949,7 @@ export default function AdminPluginsPanel() { {egressFor.hosts.map(h => (
{h} -

{t('admin.plugins.empty')}

-
@@ -1158,7 +1158,7 @@ function InstalledRow({ p, t, busy, menu, setMenu, hasUpdate, latestVer, blocked
{t('admin.plugins.updateBlocked', { reason: p.updateBlock.detail ?? p.updateBlock.code })} - @@ -1181,7 +1181,7 @@ function InstalledRow({ p, t, busy, menu, setMenu, hasUpdate, latestVer, blocked Actionable, and warning-toned until at least one host exists, because until then the plugin cannot reach anything and looks silently broken. */} {p.operatorEgress && ( - @@ -1221,7 +1221,7 @@ function InstalledRow({ p, t, busy, menu, setMenu, hasUpdate, latestVer, blocked
- @@ -1275,7 +1275,7 @@ function anchorMenu(trigger: HTMLElement | null): CSSProperties { function MenuItem({ icon, label, onClick, danger }: { icon: React.ReactNode; label: string; onClick: () => void; danger?: boolean }) { return ( - +
@@ -1426,7 +1426,7 @@ function PluginDetailModal({ item, installed, busy, onInstall, onClose, t, local

{item.author}{item.latest ? ` · v${item.latest}` : ''}

-
- {offerRetrust && ( - @@ -1685,8 +1685,8 @@ function UpdateConsentDialog({ data, unsigned, t, onApprove, onLater }: { )}
- - + +
@@ -1726,7 +1726,7 @@ function DependencyResolveDialog({ data, t, busy, installedIds, onDownload, onCl : t('admin.plugins.dep.requires', { version: r.constraint })}
- @@ -1737,7 +1737,7 @@ function DependencyResolveDialog({ data, t, busy, installedIds, onDownload, onCl )}
- +
@@ -1763,7 +1763,7 @@ function SecurityInfo({ t }: { t: T }) {

{t('admin.plugins.reviewedMeaning')}

- - @@ -274,14 +274,14 @@ export default function BackupPanel() {
- - -
- - - diff --git a/client/src/components/Admin/DefaultUserSettingsTab.tsx b/client/src/components/Admin/DefaultUserSettingsTab.tsx index 365303efa..a9bd11fc9 100644 --- a/client/src/components/Admin/DefaultUserSettingsTab.tsx +++ b/client/src/components/Admin/DefaultUserSettingsTab.tsx @@ -86,7 +86,7 @@ function OptionButton({ children: React.ReactNode }) { return ( - @@ -171,8 +171,8 @@ export default function PackingTemplateManager() { setCreateName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleCreateTemplate(); if (e.key === 'Escape') setShowCreate(false) }} placeholder={t('admin.packingTemplates.namePlaceholder')} className={inputStyle} /> - - + + )} @@ -187,7 +187,7 @@ export default function PackingTemplateManager() {
{/* Template row */}
- @@ -202,9 +202,9 @@ export default function PackingTemplateManager() { {tmpl.category_count} {t('admin.packingTemplates.categories')} · {tmpl.item_count} {t('admin.packingTemplates.items')} - -
@@ -228,11 +228,11 @@ export default function PackingTemplateManager() { {cat.name} )} {catItems.length} - - -
@@ -246,15 +246,15 @@ export default function PackingTemplateManager() { setEditItemName(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') handleRenameItem(item.id); if (e.key === 'Escape') setEditingItemId(null) }} className="flex-1 px-2 py-1 border border-slate-200 rounded-lg text-sm" /> - - + + ) : ( <> {item.name} - - )} @@ -268,9 +268,9 @@ export default function PackingTemplateManager() { onKeyDown={e => { if (e.key === 'Enter' && newItemName.trim()) handleAddItem(cat.id); if (e.key === 'Escape') { setAddingItemToCatId(null); setNewItemName('') } }} placeholder={t('admin.packingTemplates.itemName')} className="flex-1 px-2 py-1 border border-slate-200 rounded-lg text-sm" /> - - )} @@ -287,11 +287,11 @@ export default function PackingTemplateManager() { onKeyDown={e => { if (e.key === 'Enter') handleAddCategory(); if (e.key === 'Escape') { setAddingCategory(false); setNewCatName('') } }} placeholder={t('admin.packingTemplates.categoryName')} className="flex-1 px-3 py-2 border border-slate-200 rounded-lg text-sm" /> - - + + ) : ( - diff --git a/client/src/components/Admin/PermissionsPanel.tsx b/client/src/components/Admin/PermissionsPanel.tsx index acab4f0c6..6b2b149b7 100644 --- a/client/src/components/Admin/PermissionsPanel.tsx +++ b/client/src/components/Admin/PermissionsPanel.tsx @@ -104,7 +104,7 @@ export default function PermissionsPanel(): React.ReactElement {

{t('perm.subtitle')}

- -

@@ -364,7 +364,7 @@ export default function AdminStoragePanel(): React.ReactElement { {t(`storage.source.${row.source}`)} - {row.source !== 'env' && ( - )} {row.source === 'settings' && ( - )} @@ -433,7 +433,7 @@ export default function AdminStoragePanel(): React.ReactElement { failed: String(backfill.failed), })}

- - -
@@ -552,7 +552,7 @@ export default function AdminStoragePanel(): React.ReactElement { total: String(m.total), })}

- - - - @@ -87,7 +87,7 @@ export default function BudgetPanel({ tripId, tripMembers = [] }: BudgetPanelPro placeholder={t('budget.categoryName')} style={{ flex: 1, minWidth: 0, border: '1px solid var(--border-primary)', borderRadius: 10, padding: '9px 14px', fontSize: 'calc(13px * var(--fs-scale-body, 1))', outline: 'none', fontFamily: 'inherit', background: 'var(--bg-card)', color: 'var(--text-primary)' }} /> - - ))} - } + {canEdit && } ))} @@ -589,7 +589,7 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps {t('costs.youPaid')} · {fmt0(totals.myPaid)} {canEdit && ( - )} @@ -628,7 +628,7 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps
{t('costs.settleUp')} {(settlement?.flows || []).length}
{canEdit && ( - + )}
{SettleFlows()} @@ -638,7 +638,7 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps
{t('costs.expenses')}
-
{(['all', 'mine', 'owed'] as const).map(f => ( - + ))}
@@ -705,7 +705,7 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps } return (
- +
) @@ -839,8 +839,8 @@ export default function CostsPanel({ tripId, tripMembers = [] }: CostsPanelProps
{canEdit && (
- - + +
)}
@@ -970,7 +970,7 @@ function SettlementModal({ tripId, people, me, editing, currency, onClose, onSav const [cur, setCur] = useState((editing?.currency || currency).toUpperCase()) const [saving, setSaving] = useState(false) - const amt = parseFloat(amount) || 0 + const amt = Number.parseFloat(amount) || 0 const valid = amt > 0 && fromId !== toId const opts = people.map(p => ({ value: String(p.id), label: p.id === me ? t('costs.you') : p.username })) @@ -991,8 +991,8 @@ function SettlementModal({ tripId, people, me, editing, currency, onClose, onSav - - + + }>
@@ -1116,8 +1116,8 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo return calculateTicketShares(ticketItems) }, [ticketItems]) - const totalNum = isTicketMode ? ticketInfo.total : (parseFloat(total) || 0) - const splitSum = [...participants].reduce((sum, id) => sum + (parseFloat(customAmounts[id]) || 0), 0) + const totalNum = isTicketMode ? ticketInfo.total : (Number.parseFloat(total) || 0) + const splitSum = [...participants].reduce((sum, id) => sum + (Number.parseFloat(customAmounts[id]) || 0), 0) const customBalanced = Math.round(splitSum * 100) === Math.round(totalNum * 100) const each = participants.size > 0 ? totalNum / participants.size : 0 const equalShares = useMemo(() => { @@ -1130,13 +1130,13 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo const enteredSum = [...participants] .filter(id => customAmounts[id]) - .reduce((sum, id) => sum + (parseFloat(customAmounts[id]) || 0), 0) + .reduce((sum, id) => sum + (Number.parseFloat(customAmounts[id]) || 0), 0) const remaining = Math.max(0, totalNum - enteredSum) return splitEqualShares(remaining, emptyParts.map(id => ({ user_id: id })), editing?.id || 0) }, [totalNum, participants, customAmounts, editing]) - const ticketValid = ticketItems.length > 0 && ticketItems.every(item => item.name.trim().length > 0 && (parseFloat(item.price) || 0) > 0 && item.participants.size > 0) + const ticketValid = ticketItems.length > 0 && ticketItems.every(item => item.name.trim().length > 0 && (Number.parseFloat(item.price) || 0) > 0 && item.participants.size > 0) const payersOk = !multiPayer || (payerIds.size > 0 && payersBalanced(payerAmounts, payerIds, totalNum)) const valid = name.trim().length > 0 && payersOk && ( isTicketMode @@ -1263,7 +1263,7 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo // dropping the payer would store the entry with a total of 0. const payerList = multiPayer ? [...payerIds] - .map(id => ({ user_id: id, amount: parseFloat(payerAmounts[id]) || 0 })) + .map(id => ({ user_id: id, amount: Number.parseFloat(payerAmounts[id]) || 0 })) .filter(p => p.amount > 0) : payerId > 0 ? [{ user_id: payerId, amount: totalNum }] : [] // A receipt line can name somebody who is not ticked as a participant. Sending @@ -1275,7 +1275,7 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo const memberList = memberIds.map(id => ({ user_id: id, amount: splitMode === 'custom' - ? (parseFloat(customAmounts[id]) || 0) + ? (Number.parseFloat(customAmounts[id]) || 0) : splitMode === 'ticket' ? (ticketInfo.shares[id] || 0) : null @@ -1315,8 +1315,8 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo - - + +
}> {/* Two columns on desktop: what the expense was on the left, how it is @@ -1370,7 +1370,7 @@ export function ExpenseModal({ tripId, base, people, me, editing, prefill, onClo {COST_CATEGORY_LIST.map(c => { const Icon = c.Icon; const on = cat === c.key return ( - {own && canEdit && ( - } - {canEdit && {categories.map(cat => ( - } - )} - {canEdit && } - {canEdit && } - {canEdit && @@ -96,7 +96,7 @@ export function CategorySettingsModal({ onClose, categories, categoryColors, onS {/* Color swatches */}
{NOTE_COLORS.map(c => ( - - + +
@@ -50,19 +50,19 @@ export function FilePreviewPortal({ file, onClose }: FilePreviewPortalProps) {
{file.original_name}
- - + +
{(isPdf || isTxt) ? (

- +

) : (
- +
)} diff --git a/client/src/components/Collab/CollabPanel.tsx b/client/src/components/Collab/CollabPanel.tsx index e75f5e3f2..98100b01b 100644 --- a/client/src/components/Collab/CollabPanel.tsx +++ b/client/src/components/Collab/CollabPanel.tsx @@ -170,7 +170,7 @@ export default function CollabPanel({ tripId, tripMembers = [], collabFeatures } {tabs.map(tab => { const active = mobileTab === tab.id return ( - )} - @@ -47,7 +47,7 @@ export default function CollectionsWidget({ onOpen }: { onOpen: () => void }): R ) : (
{lists.slice(0, 6).map(list => ( -
- @@ -67,7 +67,7 @@ export function AssignModal(S: FileManagerState) { const placeBtn = (p: Place, idx: number) => { const isLinked = file.place_id === p.id || (file.linked_place_ids || []).includes(p.id) return ( - - - @@ -156,7 +156,7 @@ function ThumbImg({ file, active, onClick }: { file: TripFile & { url: string }; }, [file.url, fileIsVideo, visible]) return ( - - - diff --git a/client/src/components/Files/FileManagerPdfPreviewModal.tsx b/client/src/components/Files/FileManagerPdfPreviewModal.tsx index 9c3c97f54..55932dc27 100644 --- a/client/src/components/Files/FileManagerPdfPreviewModal.tsx +++ b/client/src/components/Files/FileManagerPdfPreviewModal.tsx @@ -18,21 +18,21 @@ export function PdfPreviewModal(S: FileManagerState) {
{previewFile.original_name}
- - - +

diff --git a/client/src/components/Files/FileManagerRow.tsx b/client/src/components/Files/FileManagerRow.tsx index 79fda174d..861697366 100644 --- a/client/src/components/Files/FileManagerRow.tsx +++ b/client/src/components/Files/FileManagerRow.tsx @@ -97,34 +97,34 @@ export function FileRow(p: FileManagerState & { file: TripFile; isTrash?: boolea
{isTrash ? ( <> - {can('file_delete', trip) && } - {can('file_delete', trip) && } ) : ( <> - - {can('file_edit', trip) && } - - - {can('file_delete', trip) && } diff --git a/client/src/components/Files/FileManagerToolbar.tsx b/client/src/components/Files/FileManagerToolbar.tsx index 085d7626f..2c77017e1 100644 --- a/client/src/components/Files/FileManagerToolbar.tsx +++ b/client/src/components/Files/FileManagerToolbar.tsx @@ -36,7 +36,7 @@ export function FileManagerToolbar(S: FileManagerState) { : tab.id === 'collab' ? files.filter(f => f.note_id).length : 0 return ( -
@@ -102,7 +102,7 @@ export default function ContributorInviteDialog({ journeyId, existingUserIds, on
{(['viewer', 'editor'] as const).map(r => ( -
- -
@@ -81,7 +81,7 @@ export function AddTripDialog({ journeyId, existingTripIds, onClose, onAdded }:
)} - {menuOpen && createPortal( <>
setMenuOpen(false)} />
- - + +
, document.body, @@ -113,15 +113,15 @@ export function EntryCard({ entry, readOnly, onEdit, onDelete, onPhotoClick }: {
{!readOnly && (
- {menuOpen && createPortal( <>
setMenuOpen(false)} />
- - + +
, document.body, diff --git a/client/src/components/Journey/JourneyDetailPageEntryEditor.tsx b/client/src/components/Journey/JourneyDetailPageEntryEditor.tsx index 0a8792ea6..6baaa6d65 100644 --- a/client/src/components/Journey/JourneyDetailPageEntryEditor.tsx +++ b/client/src/components/Journey/JourneyDetailPageEntryEditor.tsx @@ -209,7 +209,7 @@ export function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, trips, setPendingFiles(prev => [...prev, ...normalized]) } - const contextLocation = isValidGeoPoint({ lat: locationLat ?? NaN, lng: locationLng ?? NaN }) + const contextLocation = isValidGeoPoint({ lat: locationLat ?? Number.NaN, lng: locationLng ?? Number.NaN }) ? { lat: locationLat!, lng: locationLng!, name: locationName || undefined } : null @@ -256,7 +256,7 @@ export function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, trips,

{entry.id === 0 ? t('journey.detail.newEntry') : t('journey.detail.editEntry')}

-
@@ -275,7 +275,7 @@ export function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, trips, { (e.target as HTMLInputElement).value = '' }} className="hidden" /> { (e.target as HTMLInputElement).value = '' }} className="hidden" />
- {galleryPhotos.length > 0 && ( - )} - -
{pendingProviderGroups.length > 0 && ( - )} @@ -380,7 +380,7 @@ export function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, trips,
{availableProviders.map(provider => ( - )} - )}
))} - )}
))} - - +
diff --git a/client/src/components/Journey/JourneyDetailPageExpandableStory.tsx b/client/src/components/Journey/JourneyDetailPageExpandableStory.tsx index d26b53733..bb93db665 100644 --- a/client/src/components/Journey/JourneyDetailPageExpandableStory.tsx +++ b/client/src/components/Journey/JourneyDetailPageExpandableStory.tsx @@ -35,7 +35,7 @@ export function ExpandableStory({ story }: { story: string }) {
{clamped && !expanded && ( - )} {expanded && ( - } @@ -176,7 +176,7 @@ export function ProviderPicker({ provider, userId, entries, trips, existingAsset { id: 'all' as const, label: t('journey.picker.allPhotos'), short: t('common.all') }, { id: 'album' as const, label: t('journey.picker.albums') }, ].map(f => ( - @@ -243,7 +243,7 @@ export function ProviderPicker({ provider, userId, entries, trips, existingAsset {filter === 'album' && (
{albums.map((a: any) => ( - -
@@ -105,7 +105,7 @@ export function JourneySettingsDialog({ journey, onClose, onSaved, onOpenInvite,
-
- - - - + diff --git a/client/src/components/Journey/JourneyDetailPageVerdictSection.tsx b/client/src/components/Journey/JourneyDetailPageVerdictSection.tsx index 23fb3141b..f7ea2794a 100644 --- a/client/src/components/Journey/JourneyDetailPageVerdictSection.tsx +++ b/client/src/components/Journey/JourneyDetailPageVerdictSection.tsx @@ -9,7 +9,7 @@ export function VerdictSection({ pros, cons }: { pros: string[]; cons: string[] return (
{/* Header — clickable on mobile */} - - - {!readOnly && (
- -
- - {user?.role === 'admin' && ( -
-
)} - )} - - - - + diff --git a/client/src/components/Packing/ApplyTemplateButton.tsx b/client/src/components/Packing/ApplyTemplateButton.tsx index 7fa920f98..01de45335 100644 --- a/client/src/components/Packing/ApplyTemplateButton.tsx +++ b/client/src/components/Packing/ApplyTemplateButton.tsx @@ -59,7 +59,7 @@ export default function ApplyTemplateButton({ tripId, visibility, style, classNa return (
- ) : null} - {canEdit && } + {canEdit && }
{/* Members */}
@@ -101,7 +101,7 @@ export function BagCard({ bag, bagItems, totalWeight, pct, tripId, tripMembers, ))} {canEdit && ( - )} @@ -110,7 +110,7 @@ export function BagCard({ bag, bagItems, totalWeight, pct, tripId, tripMembers, {tripMembers.map(m => { const isSelected = memberIds.includes(m.id) return ( -
diff --git a/client/src/components/Packing/PackingListPanelBagModal.tsx b/client/src/components/Packing/PackingListPanelBagModal.tsx index 650ce8632..268b5496c 100644 --- a/client/src/components/Packing/PackingListPanelBagModal.tsx +++ b/client/src/components/Packing/PackingListPanelBagModal.tsx @@ -20,7 +20,7 @@ export function BagModal(S: PackingState) { onClick={e => e.stopPropagation()}>

{t('packing.bags')}

- +
{bags.map(bag => { @@ -66,13 +66,13 @@ export function BagModal(S: PackingState) { onKeyDown={e => { if (e.key === 'Enter') handleCreateBag(); if (e.key === 'Escape') { setShowAddBag(false); setNewBagName('') } }} placeholder={t('packing.bagName')} style={{ flex: 1, padding: '8px 12px', borderRadius: 10, border: '1px solid var(--border-primary)', fontSize: 'calc(13px * var(--fs-scale-body, 1))', fontFamily: 'inherit', outline: 'none' }} /> - ) : ( - ) : ( - diff --git a/client/src/components/Packing/PackingListPanelCategoryGroup.tsx b/client/src/components/Packing/PackingListPanelCategoryGroup.tsx index 8c2bad168..b31beb2d0 100644 --- a/client/src/components/Packing/PackingListPanelCategoryGroup.tsx +++ b/client/src/components/Packing/PackingListPanelCategoryGroup.tsx @@ -115,7 +115,7 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen return (
- @@ -165,7 +165,7 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen ))} {canEdit && (
- @@ -300,18 +300,18 @@ export function KategorieGruppe({ kategorie, items, tripId, allCategories, onRen style={{ flex: 1, padding: '6px 10px', borderRadius: 8, border: '1px solid var(--border-primary)', fontSize: 'calc(12.5px * var(--fs-scale-body, 1))', fontFamily: 'inherit', outline: 'none', color: 'var(--text-primary)', background: 'var(--bg-input)' }} /> {/* disabled while the field is empty, so no extra guard here */} - -
) : ( - - + +
)} {inlineHeader && canEdit && ( - )} {inlineHeader && canEdit && abgehakt > 0 && ( -
)} {inlineHeader && canEdit && isAdmin && items.length > 0 && !showSaveTemplate && ( - )} {bagTrackingEnabled && ( - - ) : ( -
- -
)} - )} {bags.map(b => ( - ) : ( - - @@ -344,7 +344,7 @@ export function ArtikelZeile({ item, tripId, categories, onCategoryChange: _onCa {canEdit && (
-
@@ -371,13 +371,13 @@ export default function AirTrailImportModal({ isOpen, onClose, tripId, pushUndo
- -
@@ -184,13 +184,13 @@ export default function BookingImportModal({ isOpen, onClose, tripId }: BookingI {/* Footer */}
- - )} @@ -182,14 +182,14 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri )} {!collapsed && formattedDate &&
{formattedDate}
}
- - } - {canEditDays && } @@ -468,7 +468,7 @@ function AccommodationList({ dayAccommodations, day, reservations, canEditDays, ) })} {/* Add another hotel */} - {canEditDays && } ) : ( - canEditDays ? @@ -584,7 +584,7 @@ function HotelPickerModal({ showHotelPicker, setShowHotelPicker, font, t, hotelD size="sm" /> - {categories.map(c => ( - - )} @@ -1765,7 +1765,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP const toLegIndex = legPart ? Number(legPart.slice(3)) : null if (placeId) { - onAssignToDay?.(parseInt(placeId), day.id) + onAssignToDay?.(Number.parseInt(placeId), day.id) } else if (fromReservationId && fromDayId !== day.id) { const r = reservations.find(x => x.id === Number(fromReservationId)) if (r) { const update = computeMultiDayMove(r, day.id, phase); tripActions.updateReservation(tripId, r.id, update).catch((err: unknown) => toast.error(err instanceof Error ? err.message : t('common.unknownError'))) } @@ -1791,7 +1791,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP } if (!assignmentId && !noteId && !placeId) { dragDataRef.current = null; window.__dragData = null; return } if (placeId) { - onAssignToDay?.(parseInt(placeId), day.id) + onAssignToDay?.(Number.parseInt(placeId), day.id) setDropTargetKey(null); window.__dragData = null; return } if (assignmentId && fromDayId !== day.id) { @@ -1909,7 +1909,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP const { placeId, assignmentId: fromAssignmentId, noteId, reservationId: fromReservationId, fromDayId, phase } = getDragData(e) if (placeId) { const pos = placeItems.findIndex(i => i.data.id === assignment.id) - onAssignToDay?.(parseInt(placeId), day.id, pos >= 0 ? pos : undefined) + onAssignToDay?.(Number.parseInt(placeId), day.id, pos >= 0 ? pos : undefined) setDropTargetKey(null); window.__dragData = null } else if (fromReservationId && fromDayId !== day.id) { const r = reservations.find(x => x.id === Number(fromReservationId)) @@ -2154,15 +2154,15 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP )} {canEditDays &&
- -
} {canEditDays && onAddBookingToAssignment && hoveredAssignmentId === assignment.id && ( - - + + } {canEditDays &&
- - + +
} @@ -2580,7 +2580,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP const { placeId, assignmentId, noteId, reservationId: fromReservationId, fromDayId, phase } = getDragData(e) // Neuer Ort von der Orte-Liste if (placeId) { - onAssignToDay?.(parseInt(placeId), day.id) + onAssignToDay?.(Number.parseInt(placeId), day.id) setDropTargetKey(null); window.__dragData = null; return } if (fromReservationId && fromDayId !== day.id) { @@ -2618,7 +2618,7 @@ const DayPlanSidebar = React.memo(function DayPlanSidebar(props: DayPlanSidebarP {(isSelected || (showRouteToolsWhenExpanded && isExpanded)) && routeToolsRoutable && (
- {/* Open the day's stops as a route in Google Maps (planned order). #1255 */} -
@@ -58,7 +58,7 @@ export function MobileAddPlaceButton({ dayId, places, assignments, onAssign, onA
)} {filtered.slice(0, 20).map(p => ( - - diff --git a/client/src/components/Planner/DayPlanSidebarToolbar.tsx b/client/src/components/Planner/DayPlanSidebarToolbar.tsx index e41a20b0d..94a1833ef 100644 --- a/client/src/components/Planner/DayPlanSidebarToolbar.tsx +++ b/client/src/components/Planner/DayPlanSidebarToolbar.tsx @@ -94,7 +94,7 @@ export function DayPlanSidebarToolbar({ const label = allExpanded ? t('dayplan.collapseAll') : t('dayplan.expandAll') return ( - )} - - - - @@ -47,7 +47,7 @@ export function PlacesBulkCategoryModal({ count, categories, onPick, onClose }: {categories.map(c => { const CatIcon = getCategoryIcon(c.icon) return ( - diff --git a/client/src/components/Planner/PlacesSidebarHeader.tsx b/client/src/components/Planner/PlacesSidebarHeader.tsx index c8a52e48d..a760588dc 100644 --- a/client/src/components/Planner/PlacesSidebarHeader.tsx +++ b/client/src/components/Planner/PlacesSidebarHeader.tsx @@ -30,7 +30,7 @@ export function PlacesHeader(S: SidebarState) { } = S return (
- {canEditPlaces && - )} @@ -162,7 +162,7 @@ export function PlacesHeader(S: SidebarState) { : `${categoryFilters.size} ${t('places.categoriesSelected')}` return (
- {categories.length > 0 && } {/* Minimum-stars filter (#1435), same floors as the collections bar. */} - }
diff --git a/client/src/components/Planner/PlacesSidebarListImportModal.tsx b/client/src/components/Planner/PlacesSidebarListImportModal.tsx index dc0c613dd..9ab840e43 100644 --- a/client/src/components/Planner/PlacesSidebarListImportModal.tsx +++ b/client/src/components/Planner/PlacesSidebarListImportModal.tsx @@ -25,7 +25,7 @@ export function ListImportModal(S: SidebarState) { {hasMultipleListImportProviders && (
{availableListImportProviders.map(provider => ( -
)}
- - {/* Edit */} {canEditPlaces && ( -
{!selectMode && !inDay && selectedDayId && ( - - )} {canEdit && ( -
- - @@ -561,7 +561,7 @@ function Section({ title, count, children, defaultOpen = true, accent, storageKe }, [open, storageKey]) return (
-
{canEdit && ( - - + +
, @@ -837,7 +837,7 @@ export default function ReservationsPanel({ tripId, reservations, days, assignme <>
- )} - diff --git a/client/src/components/Planner/SubscribeLinks.tsx b/client/src/components/Planner/SubscribeLinks.tsx index e5eed99ab..38ae62c3d 100644 --- a/client/src/components/Planner/SubscribeLinks.tsx +++ b/client/src/components/Planner/SubscribeLinks.tsx @@ -114,7 +114,7 @@ function UrlRow({ label, hint, url, copied, onCopy }: { }}> {url}
- )} @@ -198,7 +198,7 @@ export default function TransitJourneyModal({ reservation, onClose, onSave, onDe
{canEdit && ( - )} diff --git a/client/src/components/Planner/TransitSearchPanel.tsx b/client/src/components/Planner/TransitSearchPanel.tsx index dd8478b67..100fc4151 100644 --- a/client/src/components/Planner/TransitSearchPanel.tsx +++ b/client/src/components/Planner/TransitSearchPanel.tsx @@ -149,7 +149,7 @@ function StopPicker({ label, value, onPick, quickPicks, near, placeholder }: {
{results.length > 0 ? results.map((r, i) => ( - )) : quickPicks.map((p, i) => ( - - + +
@@ -552,7 +552,7 @@ export default function TransitSearchPanel({ day, days, places, accommodations = {MODE_GROUPS.map(m => { const active = activeModes.has(m.key) return ( -
- +
diff --git a/client/src/components/Settings/AccountTab.tsx b/client/src/components/Settings/AccountTab.tsx index e9a2488b6..84798bbb9 100644 --- a/client/src/components/Settings/AccountTab.tsx +++ b/client/src/components/Settings/AccountTab.tsx @@ -198,7 +198,7 @@ export default function AccountTab(): React.ReactElement { placeholder={t('settings.confirmPassword')} className="w-full px-3 py-2 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-slate-400 focus:border-transparent" /> -
)} - {user?.avatar_url && ( - - -
- - ))} @@ -413,7 +413,7 @@ export default function AppearanceSettingsTab(): React.ReactElement {
- - @@ -424,12 +424,12 @@ function IntegrationsMcpSection(props: any) { )}
- - @@ -526,7 +526,7 @@ function IntegrationsMcpSection(props: any) { )}

- - @@ -585,14 +585,14 @@ function McpTokenModals(props: any) {
                     {mcpCreatedToken}
                   
-
- @@ -611,11 +611,11 @@ function McpTokenModals(props: any) {

{t('settings.mcp.deleteTokenTitle')}

{t('settings.mcp.deleteTokenMessage')}

- - @@ -697,11 +697,11 @@ function OAuthClientModals(props: any) {
- - @@ -735,7 +735,7 @@ function OAuthClientModals(props: any) { {oauthCreatedClient.client_secret} - @@ -750,7 +750,7 @@ function OAuthClientModals(props: any) { )}
- @@ -769,11 +769,11 @@ function OAuthClientModals(props: any) {

{t('settings.oauth.deleteClient')}

{t('settings.oauth.deleteClientMessage')}

- - @@ -790,11 +790,11 @@ function OAuthClientModals(props: any) {

{t('settings.oauth.rotateSecret')}

{t('settings.oauth.rotateSecretMessage')}

- - @@ -818,14 +818,14 @@ function OAuthClientModals(props: any) { {oauthRotatedSecret} -
- @@ -842,11 +842,11 @@ function OAuthClientModals(props: any) {

{t('settings.oauth.revokeSession')}

{t('settings.oauth.revokeSessionMessage')}

- - diff --git a/client/src/components/Settings/LlmConnectionSection.tsx b/client/src/components/Settings/LlmConnectionSection.tsx index 67e8bcf92..bd1841655 100644 --- a/client/src/components/Settings/LlmConnectionSection.tsx +++ b/client/src/components/Settings/LlmConnectionSection.tsx @@ -143,7 +143,7 @@ export default function LlmConnectionSection(): React.ReactElement {

{t('settings.aiParsing.multimodalHint')}

-
- - )} - - - -
@@ -334,7 +334,7 @@ export default function OfflineTab(): React.ReactElement {
- - - : } + ? + : }
) } @@ -176,7 +176,7 @@ function PluginSettingsForm({ id, name, icon }: { id: string; name: string; icon ))}
{hasFields && ( - - @@ -59,7 +59,7 @@ export function SaveIndicator({ if (state.status === 'error') { return ( - diff --git a/client/src/components/Studio/SpreadView.tsx b/client/src/components/Studio/SpreadView.tsx index d5440e853..182e8957f 100644 --- a/client/src/components/Studio/SpreadView.tsx +++ b/client/src/components/Studio/SpreadView.tsx @@ -38,7 +38,7 @@ const round2 = (n: number) => Math.round(n * 100) / 100 /** #rrggbb plus an alpha, for the fades a cover panel needs. */ function hexToRgba(hex: string, alpha: number): string { - const n = parseInt(hex.slice(1), 16) + const n = Number.parseInt(hex.slice(1), 16) return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})` } diff --git a/client/src/components/Studio/StudioCanvas.tsx b/client/src/components/Studio/StudioCanvas.tsx index 518b09ce4..eaddd692b 100644 --- a/client/src/components/Studio/StudioCanvas.tsx +++ b/client/src/components/Studio/StudioCanvas.tsx @@ -394,15 +394,15 @@ export function StudioCanvas({ style={{ left: (x0 + x1) / 2, top: Math.max(6, y0 - 12) }} onPointerDown={e => e.stopPropagation()} > - {sel.length === 1 && ( <> - - @@ -417,13 +417,13 @@ export function StudioCanvas({ a rotation past the angle you wanted and back is a worse way to arrive at either. */} - - - @@ -85,7 +85,7 @@ export function Choice({ value, options, onPick, aria return (
{options.map(o => ( - - - -
@@ -236,18 +236,18 @@ export function StudioElementsPanel({ page, t }: { page: BookPageSetup; t: (k: s
{t('journey.studio.text')}
- - - - - - )} diff --git a/client/src/components/Studio/StudioExport.tsx b/client/src/components/Studio/StudioExport.tsx index e1c570ba2..c8d90798d 100644 --- a/client/src/components/Studio/StudioExport.tsx +++ b/client/src/components/Studio/StudioExport.tsx @@ -81,7 +81,7 @@ export function StudioExport({
{t('journey.studio.export')} -
@@ -109,7 +109,7 @@ export function StudioExport({
{t('journey.studio.exportFinishing')} -
- - + @@ -176,7 +176,7 @@ function Choice({
{label} {options.map(opt => ( - - - {FRAME_SHAPES.filter(sh => sh !== 'rect').map(sh => ( - - - -
diff --git a/client/src/components/Studio/StudioShell.tsx b/client/src/components/Studio/StudioShell.tsx index 383bb012e..3d5a93e0e 100644 --- a/client/src/components/Studio/StudioShell.tsx +++ b/client/src/components/Studio/StudioShell.tsx @@ -46,7 +46,7 @@ export default function StudioShell() {
{s.t('journey.studio.desktopOnlyHint')}
- - - {s.zoomPercent}% - - {/* @@ -453,7 +453,7 @@ function Workbench({ s, bookView }: { s: Studio; bookView: boolean }) { photographs, which is the thing worth passing on. */} - - - - - )}
- -
@@ -448,7 +448,7 @@ function ContentPanel({ {tab === 'photos' ? (
{photos.map(p => ( - )} {e.story && ( - )} {e.location && ( - )} @@ -508,7 +508,7 @@ function ContentPanel({ mark placed here and one the auto layout placed read alike. */} {e.date && ( - )} {e.lat != null && e.lng != null && ( - )} {e.weather && WEATHER_CONFIG[e.weather] && ( - )} {(e.pros.length > 0 || e.cons.length > 0) && ( - diff --git a/client/src/components/Studio/StudioSwatches.tsx b/client/src/components/Studio/StudioSwatches.tsx index d3fbb0ccd..0dd60c0f2 100644 --- a/client/src/components/Studio/StudioSwatches.tsx +++ b/client/src/components/Studio/StudioSwatches.tsx @@ -20,7 +20,7 @@ export function Swatches({ value, onPick }: { value: string; onPick: (c: string) return (
{SWATCHES.map(c => ( -
diff --git a/client/src/components/Studio/StudioTravelPanel.tsx b/client/src/components/Studio/StudioTravelPanel.tsx index e3a4c61c2..d0cbf9a64 100644 --- a/client/src/components/Studio/StudioTravelPanel.tsx +++ b/client/src/components/Studio/StudioTravelPanel.tsx @@ -68,7 +68,7 @@ function Card({ label, onClick, children, recommended = false, title }: { children: React.ReactNode }) { return ( - )} @@ -161,7 +161,7 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
{t(release.supportTextKey)}
{notice.cta && ( -
{notice.dismissible && ( - +
) : ( -
@@ -421,7 +421,7 @@ function DetailPane({ item, tripId, categories, members, onClose }: { const cfg = PRIO_CONFIG[p] const isActive = priority === p return ( - -
@@ -668,7 +668,7 @@ function NewTaskPane({ tripId, categories, members, defaultCategory, onCreated, const cfg = PRIO_CONFIG[p] const isActive = priority === p return ( -
- -
- - )} {canRemove && ( - - {companyHolidaysEnabled && ( - - @@ -149,10 +149,10 @@ export default function VacayPersons() { /> )}
- -
{PRESET_COLORS.map(c => ( -
-
@@ -526,7 +526,7 @@ function CalendarRow({ cal, countries, calendarType, onUpdate, onDelete }: { /> )}
- - @@ -151,10 +151,10 @@ export default function VacaySharedCalendars() { /> )}
- -
- -
- -
)} {targets.map(target => ( - @@ -956,7 +956,7 @@ export default function MAdminPluginsPanel() { {egressFor.hosts.map(h => (
{h} - @@ -1186,7 +1186,7 @@ function InstalledRow({ p, t, busy, hasUpdate, latestVer, blocked, onToggle, onU Actionable, and warning-toned until at least one host exists, because until then the plugin cannot reach anything and looks silently broken. */} {p.operatorEgress && ( - @@ -1267,7 +1267,7 @@ function EmptyState({ t, onDiscover }: { t: T; onDiscover: () => void }) {

{t('admin.plugins.empty')}

- @@ -1340,7 +1340,7 @@ function RegistryList({ items, onInstall, onOpenDetail, busy, t, installedIds, f {formatCompactCount(item.downloadCount)}
)} - +
@@ -1416,7 +1416,7 @@ function PluginDetailSheet({ item, installed, busy, onInstall, onClose, t, local

{item.author}{item.latest ? ` · v${item.latest}` : ''}

- @@ -1748,7 +1748,7 @@ function SecurityInfo({ t }: { t: T }) {

{t('admin.plugins.reviewedMeaning')}

- - - - @@ -643,12 +643,12 @@ function SidebarContent({ data, stats, countries, selectedCountry, countryDetail
- -
) : (
- ))} {countryDetail.manually_marked && onUnmarkCountry && ( - @@ -177,11 +177,11 @@ function DashboardPageDesktop(): React.ReactElement {

{t('dashboard.title')}

- - - + + +
- -
@@ -228,7 +228,7 @@ function DashboardPageDesktop(): React.ReactElement { /> ))} {tripFilter === 'planned' && !isLoading && ( -
- - - - + + + +
@@ -559,10 +559,10 @@ function TripCard({ trip, locale, badges, onOpen, onEdit, onCopy, onArchive, onD :
}
{statusLabel}
- - - - + + + +

{trip.title}

@@ -636,7 +636,7 @@ function CurrencyTool(): React.ReactElement { const currencies = rates ? Object.keys(rates).sort() : CURRENCIES const ccyOptions = currencies.map(c => ({ value: c, label: c })) const rate = rates?.[to] ?? null - const converted = rate != null ? (parseFloat(amount.replace(',', '.')) || 0) * rate : null + const converted = rate != null ? (Number.parseFloat(amount.replace(',', '.')) || 0) * rate : null const swap = () => { setFrom(to); setTo(from) } @@ -644,7 +644,7 @@ function CurrencyTool(): React.ReactElement {
{t('dashboard.currency')}
- +
@@ -652,7 +652,7 @@ function CurrencyTool(): React.ReactElement { setAmount(e.target.value)} inputMode="decimal" /> setFrom(String(v))} options={ccyOptions} searchable size="sm" style={{ marginTop: 6 }} />
- +
{t('dashboard.fx.to')}
@@ -739,7 +739,7 @@ function TimezoneTool({ locale }: { locale: string }): React.ReactElement {
{t('dashboard.timezone')}
-
@@ -757,7 +757,7 @@ function TimezoneTool({ locale }: { locale: string }): React.ReactElement {
{offsetLabel(tz)}
{timeIn(tz)}
- +
))} {zones.length === 0 && ( diff --git a/client/src/pages/HelpPage.tsx b/client/src/pages/HelpPage.tsx index 12018ebab..4d5902178 100644 --- a/client/src/pages/HelpPage.tsx +++ b/client/src/pages/HelpPage.tsx @@ -72,7 +72,7 @@ export default function HelpPage() { {/* Content */}
{/* Mobile nav toggle */} -
diff --git a/client/src/pages/InAppNotificationsPage.tsx b/client/src/pages/InAppNotificationsPage.tsx index ea66e3886..a34c3a706 100644 --- a/client/src/pages/InAppNotificationsPage.tsx +++ b/client/src/pages/InAppNotificationsPage.tsx @@ -44,7 +44,7 @@ function InAppNotificationsPageDesktop(): React.ReactElement { {/* Bulk actions */}
{unreadCount > 0 && ( - )} {notifications.length > 0 && ( - - - -
- - {canEditJourney && ( -
-
{canEditJourney && ( - + )}
@@ -320,7 +320,7 @@ function JourneyDetailPageDesktop() { { id: 'gallery' as const, icon: Grid, label: t('journey.share.gallery') }, ] ).map(v => ( - )} {canEditEntries && view === 'gallery' && ( - )} {!feedEdge.atBottom && ( - - - - - )} - - diff --git a/client/src/pages/VacayPage.tsx b/client/src/pages/VacayPage.tsx index 420d266ed..cbfa25860 100644 --- a/client/src/pages/VacayPage.tsx +++ b/client/src/pages/VacayPage.tsx @@ -48,19 +48,19 @@ function VacayPageDesktop(): React.ReactElement {
- -
{selectedYear}
- -
@@ -129,13 +129,13 @@ function VacayPageDesktop(): React.ReactElement {

{t('admin.addons.catalog.vacay.name')}

- -
- -
@@ -232,11 +232,11 @@ function VacayPageDesktop(): React.ReactElement {
- - diff --git a/client/src/pages/admin/AdminNotificationsPanel.tsx b/client/src/pages/admin/AdminNotificationsPanel.tsx index d9173075f..a62072acd 100644 --- a/client/src/pages/admin/AdminNotificationsPanel.tsx +++ b/client/src/pages/admin/AdminNotificationsPanel.tsx @@ -93,7 +93,7 @@ export default function AdminNotificationsPanel({ t, toast }: { t: (k: string) = const isOn = matrix.preferences[eventType]?.[ch] ?? true return (
-
-
- -
- - - - - - - - )} - @@ -239,8 +239,8 @@ export default function AdminUsersTab({ admin, t, locale }: AdminUsersTabProps): )}
- - + +
diff --git a/client/src/pages/atlas/AtlasCountrySearch.tsx b/client/src/pages/atlas/AtlasCountrySearch.tsx index 800a50bf4..4c7bd0855 100644 --- a/client/src/pages/atlas/AtlasCountrySearch.tsx +++ b/client/src/pages/atlas/AtlasCountrySearch.tsx @@ -113,7 +113,7 @@ export default function AtlasCountrySearch({ }} /> {search.trim() && ( -