Note editing
How an annual-statement note is stored, which version the report uses, and how a panel can view a different version than the one in use.
Two versions per note
A note can hold two bodies, both of type NoteContent (format + template):
|
The system-generated suggestion. Read-only. Absent on user-created notes. |
|
The user’s own version. Absent until the user edits or creates one. |
Which of the two the årsregnskap and PDF actually use is decided by a single persisted field, note.mode (NoteMode):
|
The report uses |
|
The report uses |
|
The note is excluded from the report. |
A note with no systemBody is custom-only (a user-created note): there is nothing to switch to, so no System/Custom toggle is shown.
Viewing ≠ using (per-panel view selection)
note.mode is persisted and shared, so historically opening the other version was switching the report to it — a mode patch, a sync, and (because mode is a reordering key) a possible note reorder, propagated to every panel.
Since #1254 the two concerns are separated:
-
In use —
note.mode, shared, what the report/PDF renders. -
Viewed — a per-panel view selection (
panelNoteState), local to one panel, changing only what that panel shows.
The selection is absolute, not a delta: absent means the panel follows note.mode; once set it never reverts on its own, so an external mode flip cannot move a panel the user has made a view choice in.
Any explicit view choice records a selection — the Systemforslag/Egendefinert pills (NoteModeControl) and enterCustom/startTextEdit (entering edit is choosing custom, so an edit session is pinned against external flips).
None of these patch, sync, or reorder anything; other panels are unaffected.
An active edit session also survives the flips themselves: looking at another version closes the editor visually (pending text flushes on unmount), and the panel reopens it when custom is shown again — the flag is cleared only by finishing the edit.
The useNoteMode composable derives the displayed version as viewSelection ?? inUseVersion, so isSystem / isCustom / uiMode are panel-local.
When the viewed version differs from the in-use one, NoteShell shows an informational not-in-use bar with two actions:
-
Ta i bruk (
takeIntoUse) — the only path that persistsnote.mode, making the shown version the one the report uses. Flushes pending edits first (reachable mid-edit) and requires edit rights. -
Gjeldende versjon (
viewInUse) — releases the selection: the panel shows the in-use version and follows future mode changes again. View-only, so it stays available in read-only/frozen mode.
A selection whose target body is missing (e.g. Tilbakestill note removed customBody) is ignored at read time — the panel falls back to the in-use version — but stays stored and resumes if the target comes back.
A selection is removed only when the panel closes or through Gjeldende versjon; the main view’s state is keyed by the per-tab id and lives for the tab.
The view selection is an open string ('system' | 'custom' today) so it can later address multiple system variants ('system:<variantId>') or shared templates ('template:<uuid>') without a data-model change.
|
Exception: first-time custom creation
"Rediger note" on a note that has no customBody yet (enterCustom) still seeds the custom body and links from the system suggestion and persists UseCustom immediately.
Creating a custom version is a deliberate act of intent to use it; only switching between two existing versions is view-only.
The three UI states
useNoteMode exposes a uiMode of NoteUiMode:
|
Showing |
|
Showing |
|
Editing the |
Entry is two-step by design: the toggle/"Rediger note" lands in viewing; a second action ("Rediger tekst", startTextEdit) opens the editor. finishTextEdit flushes pending edits and returns to viewing.
Drafts and the baseline
While editing, the edited text lives in customBody and a secure copy is kept in customBodyBaseline.
The presence of a baseline means an unapplied draft exists.
View mode is draft-inclusive (it renders customBody, the same content the PDF and the editor use), so there is no hidden draft to warn about — the older draft-review banner is disabled but retained pending the notes redesign.
This draft/baseline layer is orthogonal to the version layer above: "in use" is two-layered — which version, and within custom which body.
Per-panel state
Edit mode and the view selection are both per-panel, held in panelNoteState — one sessionStorage object per panel, keyed by the panel’s stable uuid:
-
sessionStorageis per browsing context, so state resumes on refresh and in-tab navigation, never leaks to another tab/window/client, and self-cleans when the tab closes. -
Keyed by the panel
uuid(not its index), so state follows a panel through reorder and panel-close index shifts. On full reload the uuid is re-attached by position (panelUuids). -
The main panel has no
PanelSlotProvider, so it falls back to the per-tab id (ApplicationSettings.tabId). -
Closing a panel (
closeSlot/forceCloseAllinusePanelLayoutStore) drops its whole state viaclearPanel.
Key files
|
Per-panel, per-note edit flag + view selection (sessionStorage). |
|
Version derivation, view-only transitions, |
|
The Systemforslag/Egendefinert toggle (emits; does not persist). |
|
Wires the composable, the connections row, and the not-in-use notice. |
|
Renders the body for the current |