diff --git a/components/agent-knowledge/AgentCompetenceSections.tsx b/components/agent-knowledge/AgentCompetenceSections.tsx index 92877c88..2484679a 100644 --- a/components/agent-knowledge/AgentCompetenceSections.tsx +++ b/components/agent-knowledge/AgentCompetenceSections.tsx @@ -3,15 +3,17 @@ import { useTranslations } from 'next-intl' import Link from 'next/link' import { Pin, ArrowUpRight } from 'lucide-react' -import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { SettingsGroup, SettingsRow } from '@/components/settings/SettingsRows' import type { AgentCompetence, AtomTier, FactKind, FactSource } from '@/lib/agent-context/agent-competence' /** * Read-only views of the agent's competence (domain-knowledge atoms) and top - * learned facts, for the "Vad din agent vet" overview. Each is a standalone - * Card so it can sit in its own tab. Full editable management lives in - * /settings/assistant; each links there. + * learned facts, for the "Vad din agent vet" overview. Each renders as a flat + * settings group (Fönster language) with its description behind the group + * "?" help. Full editable management lives in /settings/assistant; each + * links there. */ const TIER_ORDER: AtomTier[] = ['horizontal', 'vertical', 'modifier'] @@ -24,50 +26,43 @@ export function CompetenceCard({ competence }: { competence: AgentCompetence }) tier === 'horizontal' ? t('tier_horizontal') : tier === 'vertical' ? t('tier_vertical') : t('tier_modifier') return ( - - - {t('comp_title')} - {t('comp_desc')} - - - {atoms.length === 0 ? ( -

{t('comp_empty')}

- ) : ( - <> - {TIER_ORDER.map((tier) => { - const items = atoms.filter((a) => a.tier === tier) - if (items.length === 0) return null - return ( -
-

- {tierLabel(tier)} -

-
- {items.map((a) => ( - - {a.title} - {!a.active && tier !== 'horizontal' && ( - · {t('badge_dormant')} - )} - - ))} -
+ + {atoms.length === 0 ? ( +

{t('comp_empty')}

+ ) : ( + <> + {/* One row per tier: micro-label left, atom chips right. Dormant + atoms are the exception the outline chip variant marks. */} + {TIER_ORDER.map((tier) => { + const items = atoms.filter((a) => a.tier === tier) + if (items.length === 0) return null + return ( + +
+ {items.map((a) => ( + + {a.title} + {!a.active && tier !== 'horizontal' && ( + · {t('badge_dormant')} + )} + + ))}
- ) - })} -
- {t('comp_count', { total: atoms.length, active: activeAtoms })} - -
- - )} - - +
+ ) + })} +
+ {t('comp_count', { total: atoms.length, active: activeAtoms })} + +
+ + )} +
) } @@ -80,51 +75,49 @@ export function FactsCard({ competence }: { competence: AgentCompetence }) { s === 'composer' ? t('source_composer') : s === 'user_taught' ? t('source_user_taught') : s === 'agent_learned' ? t('source_agent_learned') : t('source_derived') return ( - - - {t('facts_title')} - {t('facts_desc')} - - - {facts.length === 0 ? ( -

{t('facts_empty')}

- ) : ( - <> -
    - {facts.map((f) => ( -
  • - {f.is_pinned ? ( - - ) : ( - - )} -
    -

    {f.content}

    -

    - {kindLabel(f.kind)} · {sourceLabel(f.source)} -

    -
    -
  • - ))} -
-
- - {factsActiveTotal > facts.length ? t('facts_more', { n: factsActiveTotal - facts.length }) : ''} - - -
- - )} -
-
+ + {facts.length === 0 ? ( +

{t('facts_empty')}

+ ) : ( + <> + {/* Flat hairline rows: fact content with its kind/source flowing + inline as muted text; the pin marks the exception. */} +
    + {facts.map((f) => ( +
  • + {f.is_pinned ? ( + + ) : ( + + )} +
    + {f.content} + + {kindLabel(f.kind)} · {sourceLabel(f.source)} + +
    +
  • + ))} +
+
+ + {factsActiveTotal > facts.length ? t('facts_more', { n: factsActiveTotal - facts.length }) : ''} + + +
+ + )} +
) } function ManageLink({ href, label }: { href: string; label: string }) { return ( - - {label} - - + ) } diff --git a/components/agent-knowledge/AgentKnowledgeView.tsx b/components/agent-knowledge/AgentKnowledgeView.tsx index 33ba0aa4..0e981b4b 100644 --- a/components/agent-knowledge/AgentKnowledgeView.tsx +++ b/components/agent-knowledge/AgentKnowledgeView.tsx @@ -3,21 +3,10 @@ import { useTranslations } from 'next-intl' import { Brain } from 'lucide-react' import { - Card, - CardHeader, - CardTitle, - CardDescription, - CardContent, -} from '@/components/ui/card' -import { Badge } from '@/components/ui/badge' -import { - Table, - TableHeader, - TableBody, - TableHead, - TableRow, - TableCell, -} from '@/components/ui/table' + SettingsGroup, + SettingsRow, + SettingsSectionHeader, +} from '@/components/settings/SettingsRows' import { AccountNumber } from '@/components/ui/account-number' import { EmptyState } from '@/components/ui/empty-state' import { formatDateLong } from '@/lib/utils' @@ -74,18 +63,14 @@ export function AgentKnowledgeView({ // already remember facts: show those rather than a dead end. return (
- - - - - -
+ +
@@ -109,126 +94,84 @@ export function AgentKnowledgeView({ ? t('period_yearly') : (vat_profile.moms_period ?? t('unknown')) - // "Regler & profil": user-authored rules + observed VAT + conventions. - // Rendered inline below the graph; Minne and Kompetens have their own - // top-level tabs, so nesting a second tab row here would just duplicate them. - const configContent = ( - <> - {explicit_rules.length > 0 && ( - - - {t('rules_title')} - {t('rules_description')} - - - - - - {t('col_rule')} - {t('col_match')} - {t('col_account')} - {t('col_vat')} - - - - {explicit_rules.map((r, i) => ( - - -
- {r.rule_name} - {t('src_rule')} -
-
- {r.match} - - {r.account_number - ? - : -} - - {vatLabel(r.vat_treatment) ?? '-'} -
- ))} -
-
-
-
- )} - -
- - - {t('vat_title')} - {t('vat_description')} - - - - - {vat_profile.registered ? t('yes') : t('no')} - - - - {periodLabel} - - - {vat_profile.treatments_used_12m.length === 0 ? ( - {t('vat_no_treatments')} - ) : ( -
- {vat_profile.treatments_used_12m.map((code) => ( - {vatLabel(code)} - ))} -
- )} -
-
-
- - - - {t('conv_title')} - {t('conv_description')} - - - - {methodLabel} - - - {conventions.voucher_series_in_use.length === 0 ? ( - - - ) : ( -
- {conventions.voucher_series_in_use.map((s) => ( - {s} - ))} -
- )} -
- - - {conventions.salary_run_active ? t('yes') : t('no')} - - - {conventions.typical_booking_lag_days !== null && ( - - {t('meta_lag_value', { days: conventions.typical_booking_lag_days })} - - )} -
-
-
- - ) - return (
{/* The cinematic hero: a self-contained dark panel with its own header */} -
-

- {t('tab_config')} -

- {configContent} + {/* "Regler & profil": user-authored rules + observed VAT + conventions, + in the flat settings language (groups under eyebrow labels, static + descriptions behind the group "?"). Minne and Kompetens have their + own top-level views, so no second tab row here. */} +
+ + + {explicit_rules.length > 0 && ( + + {explicit_rules.map((r, i) => { + const vat = vatLabel(r.vat_treatment) + return ( +
+ {r.rule_name} + + {r.match} + + + {r.account_number ? ( + + ) : ( + - + )} + {vat && · {vat}} + · {t('src_rule')} + +
+ ) + })} +
+ )} + + + + {vat_profile.registered ? t('yes') : t('no')} + + + {periodLabel} + + + {vat_profile.treatments_used_12m.length === 0 ? ( + {t('vat_no_treatments')} + ) : ( + {vat_profile.treatments_used_12m.map((code) => vatLabel(code)).join(' · ')} + )} + + + + + + {methodLabel} + + + {conventions.voucher_series_in_use.length === 0 ? ( + - + ) : ( + {conventions.voucher_series_in_use.join(', ')} + )} + + + {conventions.salary_run_active ? t('yes') : t('no')} + + {conventions.typical_booking_lag_days !== null && ( + + + {t('meta_lag_value', { days: conventions.typical_booking_lag_days })} + + + )} +

@@ -237,12 +180,3 @@ export function AgentKnowledgeView({

) } - -function Row({ label, children }: { label: string; children: React.ReactNode }) { - return ( -
- {label} -
{children}
-
- ) -} diff --git a/components/salary/TaxTableStatus.tsx b/components/salary/TaxTableStatus.tsx index cc128f7a..a644176c 100644 --- a/components/salary/TaxTableStatus.tsx +++ b/components/salary/TaxTableStatus.tsx @@ -82,7 +82,7 @@ export function TaxTableStatus({ year, compact = false }: Props) { {label} @@ -138,7 +138,7 @@ export function AccountDangerZone() { > {tRetention('account_title')} -
-
@@ -685,7 +686,7 @@ export function ApiKeysPanel() { {newKeyValue} @@ -131,8 +152,13 @@ export function BankIdSettings() { {/* QR flow: an expanding block below the row. Mounted only while linking so the BankID session starts exactly when requested. */} {isLinking && ( -
+
+ {/* BankIdAuth's own Avbryt only resets its internal session; give + the row an exit so isLinking can't get stuck. */} +
)} diff --git a/components/settings/BankNameCombobox.tsx b/components/settings/BankNameCombobox.tsx index 8e28ae55..1a22f789 100644 --- a/components/settings/BankNameCombobox.tsx +++ b/components/settings/BankNameCombobox.tsx @@ -28,9 +28,10 @@ interface BankNameComboboxProps { value?: string onChange?: (value: string) => void enableBankingEnabled?: boolean + 'aria-label'?: string } -export function BankNameCombobox({ defaultValue = '', value: controlledValue, onChange, enableBankingEnabled = false }: BankNameComboboxProps) { +export function BankNameCombobox({ defaultValue = '', value: controlledValue, onChange, enableBankingEnabled = false, 'aria-label': ariaLabel }: BankNameComboboxProps) { const isControlled = controlledValue !== undefined const [internalValue, setInternalValue] = useState(defaultValue) const value = isControlled ? controlledValue : internalValue @@ -131,6 +132,7 @@ export function BankNameCombobox({ defaultValue = '', value: controlledValue, on
- @@ -233,19 +235,14 @@ export function CalendarFeedSettings() { {feed.last_accessed_at && ( {t('last_fetched')}{' '} - {new Date(feed.last_accessed_at).toLocaleDateString('sv-SE', { - day: 'numeric', - month: 'short', - hour: '2-digit', - minute: '2-digit', - })} + {formatDateLong(feed.last_accessed_at, locale)} {' · '} {t('times_count', { count: feed.access_count })} )} diff --git a/components/settings/InvoicePaymentAccountsSettings.tsx b/components/settings/InvoicePaymentAccountsSettings.tsx index cff5dad1..e8fcd283 100644 --- a/components/settings/InvoicePaymentAccountsSettings.tsx +++ b/components/settings/InvoicePaymentAccountsSettings.tsx @@ -351,6 +351,7 @@ export function InvoicePaymentAccountsSettings({ {/* Typeahead combobox stays boxed on purpose: it is a picker, not a field. */}
updateField('bank_name', next)} enableBankingEnabled={hasBankingExtension} diff --git a/components/settings/LogoUpload.tsx b/components/settings/LogoUpload.tsx index 605bdaff..ec5d4a2b 100644 --- a/components/settings/LogoUpload.tsx +++ b/components/settings/LogoUpload.tsx @@ -135,7 +135,7 @@ export function LogoUpload({ logoUrl, onUpdate }: LogoUploadProps) { {t('logo_change')}
@@ -276,7 +276,7 @@ export function SecuritySettings() { {t('mfa_required_note')} ) : ( ) : ( {editingId && ( - )} @@ -221,11 +221,11 @@ export function TaxAssessmentNoticesPanel() {
- - diff --git a/components/settings/TemplateForm.tsx b/components/settings/TemplateForm.tsx index d348e5fe..8be5d86b 100644 --- a/components/settings/TemplateForm.tsx +++ b/components/settings/TemplateForm.tsx @@ -251,7 +251,7 @@ export function TemplateForm({ /> diff --git a/components/settings/sections/BillingSettingsContent.tsx b/components/settings/sections/BillingSettingsContent.tsx index 6e73e07d..9a910c5b 100644 --- a/components/settings/sections/BillingSettingsContent.tsx +++ b/components/settings/sections/BillingSettingsContent.tsx @@ -153,14 +153,27 @@ export function BillingSettingsContent() {
{header} - - Aktivt + + Aktivt Du kan hantera eller avsluta det när som helst. + + + Byt kort, ändra plan eller säg upp via Stripes kundportal. + +
    + {INCLUDED.map((item) => ( +
  • +
  • + ))} +
+
) } diff --git a/extensions/general/enable-banking/components/BankConnectionStatus.tsx b/extensions/general/enable-banking/components/BankConnectionStatus.tsx index e4ca5365..9a47f463 100644 --- a/extensions/general/enable-banking/components/BankConnectionStatus.tsx +++ b/extensions/general/enable-banking/components/BankConnectionStatus.tsx @@ -110,7 +110,7 @@ export function BankConnectionStatus({ {(isConnectionExpired || isConnectionError) && onReconnect && ( - @@ -135,7 +135,7 @@ export function BankConnectionStatus({ )} {isConnectionError && ( )} -
@@ -514,7 +514,7 @@ export default function BankingSettingsPanel() { Välj konton