feat: consolidate booking templates from 100 to 48 and improve codebase

Reduce booking template library to eliminate duplicate suggestions when
users describe transactions. Templates with identical accounting treatment
(same account + VAT) are merged, keywords consolidated, and the entire
subscriptions group is eliminated. Also includes prior work on reports,
extensions, and transaction improvements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-02-25 10:21:10 +01:00
co-authored by Claude Opus 4.6
parent 9d684d7e9f
commit 6956a757f3
53 changed files with 3067 additions and 2940 deletions
@@ -6,7 +6,7 @@ import {
formatExtractionSummary,
} from '../invoice-inbox-utils'
import type { InboxItemStatus } from '@/types'
import type { InvoiceExtractionResult } from '@/extensions/general/invoice-inbox/types'
import type { InvoiceExtractionResult } from '@/types'
describe('getStatusLabel', () => {
const cases: [InboxItemStatus, string][] = [
+2 -2
View File
@@ -11,8 +11,8 @@ describe('sectors registry', () => {
expect(SECTORS.length).toBe(7)
})
it('should have 22 total extensions', () => {
expect(getAllExtensions().length).toBe(22)
it('should have 24 total extensions', () => {
expect(getAllExtensions().length).toBe(24)
})
it('should have unique slugs within each sector', () => {
+1 -2
View File
@@ -1,5 +1,4 @@
import type { InboxItemStatus } from '@/types'
import type { InvoiceExtractionResult } from '@/extensions/general/invoice-inbox/types'
import type { InboxItemStatus, InvoiceExtractionResult } from '@/types'
const STATUS_LABELS: Record<InboxItemStatus, string> = {
pending: 'Väntar',
-4
View File
@@ -2,8 +2,6 @@ import { extensionRegistry } from './registry'
import { receiptOcrExtension } from '@/extensions/general/receipt-ocr'
import { aiCategorizationExtension } from '@/extensions/general/ai-categorization'
import { pushNotificationsExtension } from '@/extensions/general/push-notifications'
import { sruExportExtension } from '@/extensions/sru-export'
import { neBilagaExtension } from '@/extensions/ne-bilaga'
import { aiChatExtension } from '@/extensions/general/ai-chat'
import { invoiceInboxExtension } from '@/extensions/general/invoice-inbox'
import { calendarExtension } from '@/extensions/general/calendar'
@@ -26,8 +24,6 @@ const FIRST_PARTY_EXTENSIONS: Extension[] = [
receiptOcrExtension,
aiCategorizationExtension,
pushNotificationsExtension,
sruExportExtension,
neBilagaExtension,
aiChatExtension,
invoiceInboxExtension,
calendarExtension,
@@ -0,0 +1,27 @@
import dynamic from 'next/dynamic'
import type { ComponentType } from 'react'
/**
* Settings panel registry
*
* Maps extension IDs to dynamically imported settings panel components.
* This allows the core settings page to render extension-provided settings
* panels without directly importing from extension directories.
*/
const SETTINGS_PANELS: Record<string, ComponentType> = {
'push-notifications': dynamic(
() => import('@/extensions/general/push-notifications/NotificationSettings').then(m => ({ default: m.NotificationSettings }))
),
'enable-banking': dynamic(
() => import('@/extensions/general/enable-banking/components/BankingSettingsPanel')
),
}
/**
* Get the settings panel component for an extension.
* Returns null if the extension has no registered settings panel.
*/
export function getSettingsPanel(extensionId: string): ComponentType | null {
return SETTINGS_PANELS[extensionId] ?? null
}