Skip to content

feat: meta-type presets and TodoList system database#10

Merged
kooksee merged 15 commits into
mainfrom
feat/meta-type-presets
Jun 26, 2026
Merged

feat: meta-type presets and TodoList system database#10
kooksee merged 15 commits into
mainfrom
feat/meta-type-presets

Conversation

@kooksee

@kooksee kooksee commented Jun 25, 2026

Copy link
Copy Markdown

Summary

  • Add built-in meta-type starter presets and migrate TodoList from a page meta type to a dedicated system records database (systemKind: todo_list).
  • Ship TodoList workspace UI: sidebar quick add/recent tasks, List/Table/Board views, right-side detail panel, tags/assignees/collaborator fields, and per-record due date reminders via Scheduled Tasks.
  • Polish list interaction: compact rows, single detail surface (no todo-list modal), keyboard navigation (Esc, ↑/↓), and editable due reminders.

Test plan

  • Open TodoList from sidebar; verify list loads with Default / By status / By tags / Table / List views
  • In List view: click row or Detail → right panel updates; ↑/↓ switches tasks; Esc closes panel
  • Quick-add task from list footer and sidebar; verify recent tasks in sidebar
  • Set Target date on a task → enable due reminder; edit schedule and delete reminder
  • Create tasks from Table/Board views (no modal on todo-list page)
  • Run npm run test in packages/client (todo-list-system tests)
  • Package desktop with LOCAL_ONLY=true npm run package and smoke-test

Made with Cursor

kooksee and others added 14 commits June 24, 2026 17:11
Add new meta type presets for 'Bookmark', 'Project', 'Issue', 'Repo', 'Team', 'Events', and 'People' to enhance workspace initialization. Update the `ensurePageMetaTypes` function to seed these schemas when missing, ensuring a more comprehensive setup for new workspaces. Enhance related tests to verify the creation of these presets during workspace setup.
…itialization

Introduce a new built-in system meta type 'TodoList' with fields for task management, including 'Status', 'Priority', 'Due Date', 'Assignee', 'Estimate', and 'Labels'. Update the `ensurePageMetaTypes` function to seed this schema during workspace initialization. Enhance related tests to verify the creation and properties of the 'TodoList' meta type, ensuring a comprehensive setup for new workspaces.
…ate initialization logic

Eliminate the 'TodoList' system meta type from the initialization process, ensuring it is no longer created as part of the default meta types. Update the `ensurePageMetaTypes` function to reflect this change and adjust related tests accordingly. This refactor streamlines the workspace setup by focusing on essential meta types and their configurations.
Introduce a new link for the TodoList in the sidebar settings, allowing users to navigate to the TodoList settings page. Update the routing configuration to include the TodoList route and its corresponding mask, ensuring proper navigation and context handling for user workspaces. This enhancement improves the user experience by providing direct access to task management features.
…paceTodoListContainer

Refactor the todo list settings route by removing the database query logic for fetching the TodoList ID and replacing it with the WorkspaceTodoListContainer component. This change simplifies the routing logic and enhances the user interface by directly integrating the container for better task management experience.
…atabase management

Add new features to the todo list system, including the ability to build and manage missing views, upgrade the todo list database, and ensure proper field configurations. Refactor the todo list database creation logic to improve integration with workspace collections. Update tests to validate the new functionality and ensure comprehensive coverage of the todo list features.
Refactor the todo list system by renaming fields for clarity, introducing a new size field, and updating the sidebar menu to include a direct link to the todo list settings. Enhance the routing logic to support navigation to the new todo list modal, improving user experience and accessibility of task management features. Update tests to reflect these changes and ensure comprehensive coverage.
…sidebar improvements

Add 'Created' and 'Updated' fields to the todo list system, improving task management capabilities. Refactor sidebar components to support navigation to the todo list settings and enhance user experience. Update related tests to ensure comprehensive coverage of the new features and functionality.
…ement, and sidebar improvements

Introduce new functionalities to the todo list system, including the addition of 'Tags' and 'Assignees' fields, and improvements to view management with default settings for list views. Refactor sidebar components for better navigation to the todo list settings. Update tests to ensure comprehensive coverage of the new features and maintain functionality.
…list management

Add functionality to ensure a reminders relation field in the todo list system, improving task management capabilities. Refactor the todo list database creation and upgrade processes to include this new field. Update tests to validate the integration of reminders and ensure comprehensive coverage of the new features.
… due reminder components

Modify the layout of the RecordAttributes component to improve visual consistency by reducing the width of the field label. In the TodoListDueReminder component, enhance the logic to check for target dates before displaying due reminders, ensuring a clearer user experience. Update the workspace detail panel to include a button for clearing task selections, improving task management functionality.
…nd improved styling

Add functionality to open record modals in ListViewCollectionRow and ListViewRecordRow components, enhancing user interaction with task details. Refactor button elements for better accessibility and visual consistency, including hover effects and layout adjustments. Update ListViewQuickCreate to focus on input when triggered, improving user experience. Adjust styling across components for a more cohesive design.
Refactor the ListViewCollectionRow and ListViewRecordRow components to simplify the modal navigation logic. Consolidate the conditions for opening records and improve the clarity of the code by removing redundant navigation calls. This change enhances the user experience by ensuring a more intuitive interaction with task details.
Drop the todo-list modal child route now that list view uses the right-side detail panel exclusively. Add due reminder edit/delete, keyboard task navigation, and clearer Detail affordances.

Co-authored-by: Cursor <cursoragent@cursor.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a built-in TodoList system database along with several starter meta-type presets (such as Bookmark, Project, and Issue) to enhance workspace initialization. It also integrates the TodoList into the UI sidebar, settings, and navigation, and adds a due date reminder feature. The review feedback highlights opportunities to improve performance by avoiding sequential awaits in a loop, prevent potential runtime errors by adding defensive checks for undefined fields, support both string and date types for target dates, and avoid unnecessary re-renders by defining a stable fallback object outside of the component.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

.where('parent_id', '=', databaseId)
.execute();

for (const row of records) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Running sequential await database updates inside a for loop can be a significant performance bottleneck if there are many records. Consider batching these updates or processing them in parallel with a concurrency limit (e.g., using a batch update API or chunking with Promise.all).

Comment on lines +334 to +341
await workspace.nodes.updateNode(row.id, (draft) => {
if (draft.type !== 'record') {
return draft;
}

delete draft.fields[TODO_LIST_FIELD_IDS.assignee];
return draft;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential runtime errors, add a defensive check to ensure draft.fields is defined before attempting to delete properties from it.

      await workspace.nodes.updateNode(row.id, (draft) => {
        if (draft.type !== 'record') {
          return draft;
        }

        if (draft.fields) {
          delete draft.fields[TODO_LIST_FIELD_IDS.assignee];
        }
        return draft;
      });

Comment on lines +350 to +365
await workspace.nodes.updateNode(row.id, (draft) => {
if (draft.type !== 'record') {
return draft;
}

if (matchedUserId) {
draft.fields[TODO_LIST_FIELD_IDS.assignee] = {
type: 'string_array',
value: [matchedUserId],
};
} else {
delete draft.fields[TODO_LIST_FIELD_IDS.assignee];
}

return draft;
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Add a defensive check to ensure draft.fields is initialized before setting or deleting properties on it.

    await workspace.nodes.updateNode(row.id, (draft) => {
      if (draft.type !== 'record') {
        return draft;
      }

      if (!draft.fields) {
        draft.fields = {};
      }

      if (matchedUserId) {
        draft.fields[TODO_LIST_FIELD_IDS.assignee] = {
          type: 'string_array',
          value: [matchedUserId],
        };
      } else {
        delete draft.fields[TODO_LIST_FIELD_IDS.assignee];
      }

      return draft;
    });

Comment on lines +39 to +47
const hasTargetDate = (record: LocalRecordNode): boolean => {
const value = record.fields[TODO_LIST_FIELD_IDS.targetDate];
return Boolean(
value &&
value.type === 'string' &&
typeof value.value === 'string' &&
value.value.length > 0
);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The hasTargetDate check strictly requires value.type === 'string'. However, for a date field, the value type might be 'date' or 'string'. Relaxing this check to support both 'string' and 'date' types ensures the due date reminder can be enabled correctly.

Suggested change
const hasTargetDate = (record: LocalRecordNode): boolean => {
const value = record.fields[TODO_LIST_FIELD_IDS.targetDate];
return Boolean(
value &&
value.type === 'string' &&
typeof value.value === 'string' &&
value.value.length > 0
);
};
const hasTargetDate = (record: LocalRecordNode): boolean => {
const value = record.fields[TODO_LIST_FIELD_IDS.targetDate];
return Boolean(
value &&
(value.type === 'string' || value.type === 'date') &&
typeof value.value === 'string' &&
value.value.length > 0
);
};

Comment on lines +120 to +131
const { value, setValue } = useRecordField({
field:
remindersField?.type === 'relation'
? remindersField
: {
id: REMINDERS_RELATION_FIELD_ID,
type: 'relation',
name: 'Reminders',
index: 'z',
databaseId: '',
},
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Passing an inline fallback object to useRecordField causes a new object reference to be created on every render. If useRecordField has field in its dependency array, this will trigger unnecessary effect re-runs and re-renders. Define the fallback object as a stable constant outside the component instead (e.g., const FALLBACK_REMINDERS_FIELD = { id: REMINDERS_RELATION_FIELD_ID, type: 'relation' as const, name: 'Reminders', index: 'z', databaseId: '' };).

  const { value, setValue } = useRecordField({
    field:
      remindersField?.type === 'relation'
        ? remindersField
        : FALLBACK_REMINDERS_FIELD,
  });

Pass typed LocalRecordNode and LocalDatabaseNode into due reminder props instead of context types, and align edit permission checks with record ownership.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kooksee kooksee merged commit 20ee3a1 into main Jun 26, 2026
1 check passed
@kooksee kooksee deleted the feat/meta-type-presets branch June 26, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant