Skip to content

Workspace Types

Relevant source files

The following files were used as context for generating this wiki page:

This page documents the TypeScript type definitions that represent workspace data at different stages of processing. These types form the data model layer between the Rust backend's file system operations and the Vue frontend's reactive state.

For information about the parsed board and card document types, see Kanban Parser Schema. For information about how workspaces are loaded and managed in the frontend, see useWorkspace.

Overview

The workspace type system is organized into three layers:

  1. Raw Data Layer: WorkspaceFileSnapshot and WorkspaceSnapshot - represent unparsed file contents from the backend
  2. Selection Types: WorkspaceCardSelection and VisibleBoardCardSelection - represent user selections in the UI
  3. Indexed Data Layer: LoadedWorkspace - combines raw data, parsed results, and indexed lookups for efficient access
  4. Mutation Types: WorkspaceMutationPayload - represent atomic state updates

All types are defined in src/types/workspace.ts.

Sources: src/types/workspace.ts:1-41

Type Hierarchy

Workspace Type Relationships

Sources: src/types/workspace.ts:1-41, src/utils/workspaceSnapshot.ts:1-36

Raw Data Layer

WorkspaceFileSnapshot

Represents a single file's snapshot with its path and content.

FieldTypeDescription
pathstringRelative path from workspace root (e.g., TODO/todo.md, TODO/cards/task-1.md)
contentstringRaw markdown file content

Definition: src/types/workspace.ts:3-6

This type is used as the basic unit of file data. The Rust backend reads files from disk and creates these snapshots, which are then sent to the frontend.

Sources: src/types/workspace.ts:3-6

WorkspaceSnapshot

Represents the complete raw workspace state returned from the backend.

FieldTypeDescription
rootPathstringAbsolute file system path to workspace root directory
rootBoardPathstringRelative path to the root board file (typically TODO/todo.md)
boardsWorkspaceFileSnapshot[]Array of all board file snapshots in the workspace
cardsWorkspaceFileSnapshot[]Array of all card file snapshots in the workspace

Definition: src/types/workspace.ts:8-13

This is the primary data structure returned by the load_workspace Rust command (see Backend Command Handlers). It contains no parsed or indexed data - just raw file paths and contents.

Example structure:

typescript
{
  rootPath: "/Users/name/projects/my-project",
  rootBoardPath: "TODO/todo.md",
  boards: [
    { path: "TODO/todo.md", content: "# Main Board\n\n## Todo\n..." },
    { path: "project-a/TODO/todo.md", content: "# Project A\n..." }
  ],
  cards: [
    { path: "TODO/cards/task-1.md", content: "---\ntitle: Task 1\n---\n..." },
    { path: "TODO/cards/task-2.md", content: "---\ntitle: Task 2\n---\n..." }
  ]
}

Sources: src/types/workspace.ts:8-13, src/utils/workspaceSnapshot.ts:5-6, src/utils/boardMarkdown.test.ts:198-203

Selection Types

WorkspaceCardSelection

Represents a card that is currently selected by the user.

FieldTypeDescription
slugstringFull card slug (e.g., TODO/cards/task-1)
sourceBoardSlugstringSlug of the board containing this card (e.g., TODO)

Definition: src/types/workspace.ts:15-18

This type identifies a selected card by its slug and the board it belongs to. The sourceBoardSlug is necessary because the same card might be visible on multiple boards through sub-board relationships.

Sources: src/types/workspace.ts:15-18

VisibleBoardCardSelection

Extends WorkspaceCardSelection with positional information for cards visible on the current board.

FieldTypeDescription
slugstringInherited from WorkspaceCardSelection
sourceBoardSlugstringInherited from WorkspaceCardSelection
columnIndexnumberZero-based index of the column containing this card
rowIndexnumberZero-based index of the card within its column

Definition: src/types/workspace.ts:20-23

This extended type is used for keyboard navigation and multi-selection features (see useBoardSelection). The columnIndex and rowIndex fields enable arrow key navigation and range selection.

Sources: src/types/workspace.ts:20-23

Mutation Layer

WorkspaceMutationPayload

Represents an atomic workspace state update, typically resulting from a user action.

FieldTypeDescription
currentBoardSlugstring | null | undefinedOptional: new current board slug to navigate to
selectedCardWorkspaceCardSelection | null | undefinedOptional: new card selection state
snapshotWorkspaceSnapshotRequired: updated workspace snapshot from backend

Definition: src/types/workspace.ts:25-29

This type is used when backend operations complete and return updated workspace state. It bundles the new snapshot with optional navigation/selection updates. The undefined vs null distinction matters:

  • undefined: don't change this aspect of state
  • null: explicitly clear this aspect of state
  • Non-null value: set to this value

Usage pattern:

typescript
// After saving a card, update workspace and maintain selection
const payload: WorkspaceMutationPayload = {
  selectedCard: undefined,  // keep current selection
  snapshot: updatedSnapshot  // new workspace state
}

// After deleting a card, update workspace and clear selection
const payload: WorkspaceMutationPayload = {
  selectedCard: null,       // clear selection
  snapshot: updatedSnapshot
}

// After creating a board, navigate to it
const payload: WorkspaceMutationPayload = {
  currentBoardSlug: newBoardSlug,  // navigate to new board
  snapshot: updatedSnapshot
}

Sources: src/types/workspace.ts:25-29

Indexed Data Layer

LoadedWorkspace

Represents a fully processed workspace with parsed documents and indexed lookups.

FieldTypeDescription
rootPathstringWorkspace root absolute path
rootBoardSlugstringSlug of the root board (e.g., TODO)
snapshotWorkspaceSnapshotOriginal raw snapshot from backend
parseResultKanbanParseResultParsed board and card documents with diagnostics
boardsBySlugRecord<string, KanbanBoardDocument>Map for O(1) board lookup by slug
boardFilesBySlugRecord<string, WorkspaceFileSnapshot>Map for O(1) board file lookup by slug
cardsBySlugRecord<string, KanbanCardDocument>Map for O(1) card lookup by slug
boardOrderstring[]Ordered array of board slugs for iteration

Definition: src/types/workspace.ts:31-40

This is the primary data structure used by the frontend. It combines:

  1. Raw snapshot data for reference and persistence
  2. Parsed, typed documents from KanbanParseResult (see Kanban Parser Schema)
  3. Indexed maps for efficient lookups by slug
  4. Ordered arrays for deterministic iteration

The LoadedWorkspace is constructed by the buildLoadedWorkspace() function, which takes a WorkspaceSnapshot and transforms it into this indexed structure.

Sources: src/types/workspace.ts:31-40, src/utils/workspaceSnapshot.ts:5-27

Transformation Pipeline

Data Flow from Backend to Frontend State

Sources: src/utils/workspaceSnapshot.ts:5-27, src/utils/parseWorkspace.ts

Helper Functions

buildLoadedWorkspace

Transforms a WorkspaceSnapshot into a LoadedWorkspace by parsing and indexing the data.

Signature: buildLoadedWorkspace(snapshot: WorkspaceSnapshot): LoadedWorkspace

Location: src/utils/workspaceSnapshot.ts:5-27

Implementation overview:

  1. Parse snapshot using parseWorkspace() to get KanbanParseResult
  2. Build boardsBySlug map from parsed boards
  3. Build boardFilesBySlug map using boardIdFromBoardPath() helper
  4. Build cardsBySlug map from parsed cards
  5. Extract boardOrder array from parsed boards
  6. Compute rootBoardSlug from snapshot.rootBoardPath

Sources: src/utils/workspaceSnapshot.ts:5-27, src/utils/kanbanPath.ts:88-90

createWorkspaceSnapshotSignature

Creates a stable string signature for comparing workspace snapshots.

Signature: createWorkspaceSnapshotSignature(snapshot: WorkspaceSnapshot): string

Location: src/utils/workspaceSnapshot.ts:29-35

This function serializes the snapshot to JSON for comparison purposes. It's used to detect when a workspace has changed and needs re-parsing. The signature includes rootBoardPath, boards, and cards arrays.

Sources: src/utils/workspaceSnapshot.ts:29-35

Usage Patterns

Loading a Workspace

typescript
// 1. Backend returns WorkspaceSnapshot
const snapshot: WorkspaceSnapshot = await invoke('load_workspace', { path })

// 2. Transform into LoadedWorkspace
const loaded = buildLoadedWorkspace(snapshot)

// 3. Access indexed data
const rootBoard = loaded.boardsBySlug[loaded.rootBoardSlug]
const card = loaded.cardsBySlug['TODO/cards/task-1']

Sources: src/utils/workspaceSnapshot.ts:5-27

Applying Mutations

typescript
// After a backend operation that modifies files
const payload: WorkspaceMutationPayload = {
  currentBoardSlug: undefined,  // maintain navigation
  selectedCard: { 
    slug: 'TODO/cards/new-card',
    sourceBoardSlug: 'TODO'
  },
  snapshot: updatedSnapshot  // from backend
}

// Transform and apply to state
const newLoaded = buildLoadedWorkspace(payload.snapshot)
// Update reactive state with newLoaded and payload.selectedCard

Sources: src/types/workspace.ts:25-29

Iterating Boards in Order

typescript
// Use boardOrder for deterministic iteration
for (const boardSlug of loaded.boardOrder) {
  const board = loaded.boardsBySlug[boardSlug]
  const boardFile = loaded.boardFilesBySlug[boardSlug]
  // Process board...
}

Sources: src/types/workspace.ts:39, src/utils/workspaceSnapshot.ts:14

Type Safety Benefits

The workspace type system provides several type safety guarantees:

  1. Separation of Concerns: Raw data (WorkspaceSnapshot) is clearly separated from parsed data (LoadedWorkspace)
  2. Explicit Nullability: The mutation payload uses T | null | undefined to distinguish between "keep", "clear", and "set" operations
  3. Indexed Access: The Record<string, T> maps in LoadedWorkspace ensure type-safe lookups
  4. Immutability: All types are interfaces with readonly semantics (no mutating methods)

Sources: src/types/workspace.ts:1-41

For types related to the parsed board and card documents stored in LoadedWorkspace, see:

For information about how these types are used in the application state, see:

Sources: src/types/workspace.ts:1