Phase 3 of dev_docs/dimensions_implementation_plan.md. Companies with dimensions_enabled=false see zero change; existing free-text API writers keep working (validation is toggle-governed). Engine (soft validation): - validateEntryDimensions() in dimension-resolver: zero queries for untagged entries; toggle off → passthrough; toggle on → one settings fetch + two registry queries, rejects unknown dims/codes and archived values with Swedish per-code messages (DimensionValidationError, 400, details.issues). Wired into createDraftEntry + updateDraftEntry before any insert; reversal/ storno paths untouched (verbatim copies). Fails open on transient registry errors — soft validation must never block bookkeeping. MCP (agent write path): - New tools: gnubok_list_dimensions, gnubok_list_dimension_values (fuse.js fuzzy), gnubok_create_dimension_value (STAGED via pending_operations — agents never silently mint reporting values; new op type + CHECK migration + executor with duplicate-idempotency). - create_voucher/correct_entry: per-line dimensions bag + default_dimensions, resolve-don't-select server-side (code OR natural-language name; exact → fuzzy ≤0.30 with ≥0.15 runner-up margin; non-exact resolutions echoed with confidence; ambiguous → ranked candidates, no auto-create). - gnubok_get_agent_briefing gains a dimensions block (enabled, dims, top values) — omitted when registry empty. - TOOL_SCOPE_MAP entries; risk tier low for staged value creation. UI: - JournalEntryForm (manual voucher + TransactionBookingDialog embed): header "+ Kostnadsställe/Projekt" progressive disclosure (gäller alla rader with documented inheritance rule) + per-row tag popover + compact KS·PR badges; gated on dimensions_enabled. - Voucher detail: display-only dimension badges with registry-name resolution. - EditDraftEntryDialog carries line dimensions so editing a draft no longer strips tags. categorize/bulk_book dims deferred to PR7 (needs the bulk_book RPC migration). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
'use client'
|
|
|
|
import { Label } from '@/components/ui/label'
|
|
import DimensionCombobox from '@/components/dimensions/DimensionCombobox'
|
|
|
|
interface LineDimensionFieldsProps {
|
|
/** Current dimensions map ({sie_dim_no: object_code}) — a line's map or the header default. */
|
|
dimensions: Record<string, string> | undefined
|
|
/** Fired per dimension; `code === null` clears the value. */
|
|
onChange: (sieDimNo: string, code: string | null) => void
|
|
disabled?: boolean
|
|
/** Vertical layout for narrow containers (row popover); default is a 2-col grid. */
|
|
stacked?: boolean
|
|
/** Extra classes merged into the combobox inputs (pass 'h-8' for dense contexts). */
|
|
inputClassName?: string
|
|
}
|
|
|
|
/**
|
|
* The Kostnadsställe + Projekt combobox pair (SIE dims 1/6) used by the
|
|
* voucher form's header default, the per-row tag popover, and the mobile line
|
|
* cards. Labels are the seeded system-dimension names and hardcoded Swedish —
|
|
* the component mounts on the voucher editor, a stays-Swedish surface per
|
|
* .claude/rules/i18n.md (same convention as DimensionCombobox).
|
|
*/
|
|
export default function LineDimensionFields({
|
|
dimensions,
|
|
onChange,
|
|
disabled,
|
|
stacked,
|
|
inputClassName,
|
|
}: LineDimensionFieldsProps) {
|
|
return (
|
|
<div className={stacked ? 'space-y-3' : 'grid grid-cols-2 gap-3'}>
|
|
<div>
|
|
<Label className="text-xs text-muted-foreground">Kostnadsställe</Label>
|
|
<div className="mt-1">
|
|
<DimensionCombobox
|
|
sieDimNo="1"
|
|
value={dimensions?.['1'] ?? null}
|
|
onChange={(code) => onChange('1', code)}
|
|
disabled={disabled}
|
|
className={inputClassName}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<Label className="text-xs text-muted-foreground">Projekt</Label>
|
|
<div className="mt-1">
|
|
<DimensionCombobox
|
|
sieDimNo="6"
|
|
value={dimensions?.['6'] ?? null}
|
|
onChange={(code) => onChange('6', code)}
|
|
disabled={disabled}
|
|
className={inputClassName}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|