Eddy Dev Handbook
Architecture

Sheet Architecture

An overview of the Sheets feature, covering core concepts, UI components, data flow, and state management.

Source: This page is based on docs/SHEETS.md

This document provides a developer-focused overview of the Sheets feature in Project Eddy. It covers the core concepts, key components, data flow, and state management that power the tabular data experience.

1. Core Concepts

Sheets are the primary data storage mechanism within Project Eddy, acting as workspace-level databases that can be linked to workflows. They provide a familiar spreadsheet-like interface for viewing and managing records.

  • Sheet (sheets table): The top-level container for a set of records, belonging to a group. It holds metadata like the sheet's name and author.
  • Column (columns table): Defines the schema of a Sheet. Each column has a name, a data type (e.g., text, number, date), and an order.
  • Row (rows table): A single record within a Sheet. Each row can be optionally linked to a specific workflow_run, creating a direct connection between a process instance and its data.
  • Cell (cells table): The atomic data value at the intersection of a row and a column.
  • Sheet View (sheet_views table): A saved configuration for a Sheet that includes filters, search terms, column order, and column visibility. This allows users to create and switch between different customized views of the same underlying data.

2. Key UI Components & Functional Areas

The primary interface for Sheets is the page at /workspaces/[groupId]/sheets/[sheetId], which is built around a powerful data grid and a comprehensive set of management tools.

A. The Data Grid (Ag-Grid)

This is the central component for displaying and interacting with sheet data.

  • Component: AgGridReact from the @ag-grid-community library.
  • Functionality:
    • Renders all rows and columns for the sheet.
    • Handles client-side sorting, filtering, and column movement.
    • The grid's column definitions are dynamically generated by the toAgGridColDefs utility (app/components/sheet/sheet-utils.ts), which maps our application's column schema to Ag-Grid's configuration.
  • Customization:
    • Custom Headers (AgCustomHeaderEdit.tsx): Headers are customized to show sorting indicators and, in Edit Mode, an icon to open the column editor.
    • Custom Cell Renderers (app/components/sheet/cell-renderers/): The cellRendererSelector function maps column types to specific React components for rich data display. Examples include AgCellDate (with a "add to calendar" feature), AgCellAttachment, and AgCellLongText (which opens a modal for long content).
    • Action Cell (AgCellActions.tsx): A special renderer for the "Actions" column that provides quick links to the associated record, workflow, and session, as well as an option to archive the row.

B. The Top Bar (SheetTopBar.tsx)

This component serves as the main control panel for the sheet.

  • Component: SheetTop
  • Functionality:
    • Sheet Title: Displays the sheet's name, which becomes an input field in "Edit Mode" to allow for quick renaming (POST /api/sheets/update).
    • Search & Filtering: Provides a simple text search input and a QueryBuilderPopover for creating complex, rule-based filters.
    • View Management (SheetViewsDropDown.tsx): An async-creatable select dropdown that allows users to load existing views (POST /api/sheet_views) or create new ones (POST /api/sheet_views/create).
    • Action Bar: A menu containing all major sheet-level actions.

C. Action Bar & Modals

The Action Bar, triggered from the Top Bar, provides access to key management features, each typically opening its own modal.

  • Edit Mode: Toggles the sheet's UI between a read-only data consumption mode and a management mode where columns can be edited and the sheet's name can be changed.
  • Column Management (ColumnModal.tsx): A single modal for creating (POST /api/columns/create) and updating (POST /api/columns/update) columns. It includes validation to prevent duplicate column names.
  • Sheet Deletion (sheet-components/DeleteModal.tsx): A confirmation modal for archiving the entire sheet. Crucially, it first calls the POST /api/sheets/bound_data endpoint to check if the sheet is used by any workflows, blocks, or sections. It displays these dependencies to the user as a warning before allowing the deletion to proceed.
  • Sharing (ShareSheetModal.tsx): Opens a modal to invite other workspace members or new users via email to collaborate on the sheet (POST /api/sheets/share).
  • Export: Triggers a client-side CSV export of the current grid data, including sanitization logic to format the data correctly.

3. Data Flow & State Management

The sheet page is a data-intensive application that relies on React Query for server state and a combination of useState and useRef for client-side UI state.

  • Initial Load:
    • The useGetSheetDataBySheet hook is the primary data source, making a single API call to POST /api/sheets/data/sheet to fetch the sheet itself, along with all its columns, rows, and cells.
    • Permissions are checked using defineSheetAbilityForMember to determine if the current user canRead or canManage the sheet, which gates access to UI elements.
  • Mutations:
    • All write operations follow a standard pattern: a user action triggers a mutation hook (e.g., useUpdateColumn, useReorderColumns, useDeleteSheetMutation).
    • The hook makes a POST request to the relevant API endpoint.
    • On success, the hook uses queryClient.invalidateQueries to invalidate the ['sheetDataBySheet', sheetId] cache key, triggering a refetch and causing the UI to re-render with the latest data from the server.
  • Client-Side State:
    • useState: Manages transient UI state such as the current search term, the advanced filter query object, the sheet mode (read vs. edit), and the selectedView.
    • localStorage: The showArchivedRows preference is persisted in local storage on a per-sheet basis to remember the user's choice across sessions.
    • useRef: Used extensively to interact with the Ag-Grid instance (gridApiRef) and to act as a debounce flag (isColumnMoveInProgressRef) to prevent duplicate API calls during rapid column reordering.

4. Key Features & Logic

Several key features are powered by a combination of frontend logic and backend APIs.

  • Column Reordering:
    • The onColumnMoved event handler in Ag-Grid is used to detect when a user finishes dragging a column.
    • It calculates the column's new target order and calls the appropriate mutation: useReorderSheetViewsColumn if a view is active (to save the order to the view) or useReorderColumns if no view is selected (to save the order to the sheet's default).
  • Filtering & Views:
    • The QueryBuilderPopover component provides a UI for building a RuleGroupType object.
    • This query object, along with the search string, is passed to Ag-Grid's external filter functions (isExternalFilterPresent and doesExternalFilterPass), which use the filterRow utility to perform client-side filtering.
    • When a user saves or updates a view, the current query and search state is persisted to the database via useUpdateSheetView.
  • Column Visibility:
    • Hiding a column is a view-specific setting. When a user hides a column, the addFlagHideToColumn function updates the column_options array on the selected view object and persists it using updateSheetViewMutation.
    • The HiddenColumnTags component renders a list of hidden columns and provides a way to un-hide them.
  • Safe Deletion:
    • To prevent breaking workflows that depend on a sheet, the deletion process is carefully managed.
    • The frontend's SheetDeleteModal first checks for dependencies by fetching bound data.
    • If the user confirms, the POST /api/sheets/delete endpoint is called. The backend logic first unbinds the sheet from all associated workflows, blocks, and sections (by nullifying their sheet_id references) before finally soft-deleting the sheet by setting its archived_at timestamp.

On this page