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):

systemBody

The system-generated suggestion. Read-only. Absent on user-created notes.

customBody

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):

UseSystem

The report uses systemBody.

UseCustom

The report uses customBody.

NotUsed / ManuallyRemoved

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 usenote.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 persists note.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:

system

Showing systemBody, read-only.

customViewing

Showing customBody, not editing the body text (links/figures still editable).

customEditing

Editing the customBody text.

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:

  • sessionStorage is 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 / forceCloseAll in usePanelLayoutStore) drops its whole state via clearPanel.

Key files

panelNoteState.ts

Per-panel, per-note edit flag + view selection (sessionStorage).

useNoteMode.ts

Version derivation, view-only transitions, takeIntoUse, edit-mode state.

NoteModeControl.vue

The Systemforslag/Egendefinert toggle (emits; does not persist).

NoteShell.vue

Wires the composable, the connections row, and the not-in-use notice.

NoteBody.vue

Renders the body for the current uiMode.