Skip to content

feat(database): add Notion-style dashboard view - #563

Open
appflowy wants to merge 87 commits into
mainfrom
feat/dashboard-view
Open

appflowy wants to merge 87 commits into
mainfrom
feat/dashboard-view

Conversation

@appflowy

@appflowy appflowy commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

Adds Dashboard database views with embedded views from one or more databases, private widget filters and sorts, global filters, chart drill-down, and shared editing.

Web and Desktop now use the same dashboard rules:

  • No total widget limit or per-row limit. Adding, duplicating, moving, saving, and reloading preserve every widget and its logical row.
  • Row widths use an integer budget of max(12, widget count). Responsive wrapping preserves saved identities and matches Desktop, including uneven widths and the four-widget layout.
  • Chart aggregation and empty-value settings retain their wire encoding, including legacy aggregation values and unknown fields.
  • Text and URL chart drill-down uses the clicked row membership when grouping normalizes text or uses its first letter.
  • Private conditions remain separate from source-view settings. Saving applies the intended edits, and closing a widget releases its private state.

The 114 shared fixture files match Desktop byte for byte. FIXTURES.sha256 has SHA-256 9f2df72d7f634d8ce6476c1f0ab27acec6fe46e40d17c359e0b882a23b7d5719.

Validation:

  • 112 dashboard Jest suites / 2,400 tests passed. Focused shared-fixture, geometry, and legacy chart compatibility suites passed.
  • Follow-up validation: 142 drill-down tests, 7 cache persistence tests, 20 row split/duplicate tests, and 73 add-widget tests passed.
  • Repository TypeScript checking, source ESLint, and BDD generation passed. Matching Web/Desktop scenarios require a normal enabled add button beyond twelve widgets and preserve a fifth duplicated widget in its row.
  • Remote coverage for f8eb2e27: 1,050 suites and 18,224 tests passed, with 2 skipped. Web build and Docker runtime checks passed on the verified PR merge revision. Browser integration CI completed. One dashboard shard has six failures: three larger-layout persistence checks against the older Server runtime and three field-creation setup errors; the other browser jobs passed.

Server PR #1459 merged as 3a6f246b. Browser CI still uses Server 0.20.5 (3e620bb7), so larger layout writes need a runtime containing the merged change. Browser fixture setup also intermittently returns server error 1017; the retained Web logs do not establish its cause. Server follow-up #1460 addresses a definite field-publication refusal reproduced in Server CI; its service-backed validation is pending. No deployment is included.

Desktop companion: AppFlowy-Premium #1389.

appflowy and others added 17 commits September 17, 2026 04:24
A Dashboard database view (DatabaseViewLayout 9, ViewLayout 11) shows a
row-based grid of widgets. Each widget renders another database view, from
this or any other database in the workspace, with its own filters, sorts
and settings.

- View and Edit modes; Edit adds widget headers, drag to move, width and
  row-height handles, a widget menu and an add-widget picker for existing
  or new views. Limits: 12 widgets, 4 per row, 12-column widths.
- Dashboard global filters ("Filter multiple sources") map one property per
  source database and are AND-ed with each widget's own view filters;
  View-mode changes stay local until "Save for everybody".
- New Number chart type for KPI tiles.
- Registration across tabs, layout switcher, icons, app shell, publish and a
  Linked Dashboard slash item.
- Unit tests and a 50-scenario Playwright BDD suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…perty order

- generateNiceTicks rounded ticks by float multiplication, so small ranges
  rendered labels such as 0.30000000000000004 (clipped to "0001"). Ticks are
  now rounded to the step's precision, and whole-number data (counts) gets
  whole-number steps.
- A chart without an X axis picked the first groupable field in Y.Map
  iteration order, which depends on how the doc was built (a date field
  could win over a select field). It now follows the view's field_orders,
  like desktop's select_chart_group_field.

test(dashboard): make the dashboard BDD suite pass (50/50)

- Take fixture view ids from the workspace database list: a container
  database's doc also holds a hidden inline view no folder view points at.
- Re-enter Edit mode after seeding widgets into a new dashboard (it falls
  back to View mode when widgets arrive without the picker).
- Invite members into a custom space: private spaces have no roster.
- Compare server and browser layouts with sorted object keys.
- Measure both ends of a cross-row widget drag in one scroll position.
- The sidebar lists database views with a dot, not the layout icon.
- The empty-database Number chart scenario configures both charts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rows, widgets and global filters stored without an id, and rows that spill
over the four-widget limit, got random ids on every parse. A setting held
as a Y.Array is re-parsed on every read (toJSON returns a new array, so the
per-value cache misses), so each read looked like a layout change: the
layout store returned a new snapshot on every getSnapshot call and
useSyncExternalStore could loop. Fallback ids are now positional
(r:<row>, w:<row>:<index>, gf:<index>) and spill rows use <row id>:<chunk>.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- A Number chart using Count (or without a Y field) only needs the row
  orders, so it no longer calls ensureRow for every row. The drill-down
  popup loads the rows it lists that are not open yet.
- The Number chart value is memoized on the aggregation, the Y field and
  the rows only, so title, number format and X-axis edits do not recompute
  it, and its item keeps its identity while the value and row ids do.
- The Number chart title input is keyed by the stored title instead of
  copying it into state in an effect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
DatabaseActions imported DashboardActions statically, which pulled the
global filter editor (through the global-filters barrel) into every
database view's bundle. DashboardActions is now a lazy component rendered
only for dashboards, and it imports GlobalFilterButton from its own file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…road subscriptions

- Dashboard extra filters move from the DatabaseContext value to a
  DatabaseExtraFiltersContext that Database provides and only
  useRowOrdersSelector reads, so a global filter change no longer
  re-renders every database context consumer of a widget.
- DashboardSettings subscribes to the widget-title flag alone
  (useDashboardShowWidgetTitles) instead of the whole dashboard layout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- DashboardContext keeps the layout and mode; global filters move to
  DashboardFiltersContext and source docs / names to
  DashboardSourcesContext, so registering a source no longer re-renders
  every widget's database and filter edits leave the grid alone.
- Global filter sources use one cached store per source doc
  (useSyncExternalStore): one set of Yjs observers per doc however many
  components list it, only the listed docs are observed, a change re-reads
  only its doc and unchanged property lists keep their identity, and the
  unconditional re-read on mount is gone.
- The filter bar mounts the sources hook only while it shows chips;
  GlobalFilterBar, GlobalFilterChip, the editor's target rows, condition
  select and value control are memoized, and the debounced name input is
  its own component.
- Chip labels are memoized and condition labels come from a cached map;
  activity is computed once per label.
- The filter menu returns to the list while rendering when the edited
  filter disappears (no empty frame); the property picker and addable
  sources are computed once per source list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/components/database/components/tabs/AddViewButton.tsx
…line

The cloud requires an active Pro plan to create a Dashboard view on hosted
release builds, so the add-view menu disables the Dashboard entry with an
explanation instead of failing on the server. It reuses the Timeline plan
check (and its per-workspace cache) with a Dashboard message.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… widgets

Second React best-practices review of the dashboard.

- Widgets read only stable contexts: host services (DashboardHostContext),
  UI plumbing with getRows/updateRows, and the dragged widget id in its own
  context. Edit state and titles arrive as props, and the nested database is
  memoized, so a row resize, drag start or host row-map change no longer
  re-renders every widget's database.
- The widget menu computes its move / duplicate state from the rows while it
  is open, so widget actions stay stable.
- The layout store reuses unchanged row, widget and filter objects.
- A row-height drag defers the nested database's height; resize handles set
  touch-action: none so touch drags are not cancelled.
- The widget picker defers its query and memoizes the option groups.
- A local filter override equal to the saved filters is dropped, so the
  "only you see these changes" badge no longer sticks.
- Switching dashboard views resets Edit mode and local filters during render.
- Source registration callbacks have their own stable context, and
  useGlobalFilterSources keeps its list while nothing it lists changed.
- The filter editor passes plain values to its rows and controls, so saving
  the name re-renders none of them.
- The Number chart title input follows the stored title during render
  instead of remounting, so Enter keeps focus and remote edits keep a draft.

DashboardProvider stays an eager import: lazy-loading it put a Suspense
boundary around the whole database view (the tab bar blanked while the
chunk loaded, and Edit mode came up a render after the dashboard).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Row docs are mutated in place, so editing a value a chart reads (a Value
typed into a table widget next to a Number chart on a dashboard, or a
collaborator's edit) changed neither the row orders nor the row map and the
chart kept its stale total. Observe the row data of the charted rows and
recompute at most once per frame.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Widgets and rows can be addressed by a view's own name (viewsByName), and
  opening a row from a widget works for list, board, gallery and timeline
  widgets, not only tables.
- Fixture databases can be described by a spec (property names, types and
  select options with name-derived ids shared across databases).
- Template-data pruning checks the removed field ids, so a database may have
  its own "Type" property.
- registerDashboardWorld for scenarios that build their own workspace; the
  member browser takes an optional viewport.
- A global filter chip changed in View mode is local: only the chip is
  checked then.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven features (28 scenarios) modelled on Notion's dashboard templates:
sales pipeline, bug triage, team status across two databases, executive
KPI review, daily planner, company home across three databases and
personal finance. Given steps build databases, rows, views (filters, sorts,
grouping, chart / calendar / timeline settings) and dashboards through the
cloud API and one Yjs transaction per view, then wait for the server to hold
them; When steps drive the real UI (picker, width handles, board drag,
table cells, row pages, chart drill-down, "Filter multiple sources").

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Yjs values read inside page.evaluate are untyped, so allow `any` in the
helper file, and add the missing blank line before a statement.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
On a busy machine the dev server occasionally fails a dynamic import and
the app shows one of its error screens ("Couldn’t load this page",
"Something went wrong", or the element fallback). The dashboard test bridge
now reloads the tab like a user would (at most three times per tab), so a
fixture navigation does not time out waiting for the database to mount.
It only reloads after the page reported a failed dynamic import: those
screens also catch real render errors, which must still fail the scenario.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The cell-edit observer reacted to any change in a charted row (other
columns, row height, the last-modified stamp), so every edit next to a
large grid made each chart re-read all rows. Watch only the X / Y cells
(and the row timestamps when grouping by created or edited time), read
from a ref so settings changes never re-subscribe, and keep the row-order
array while its ids are unchanged so a filtered view's late re-emit does
not recompute again.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ript

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@sourcery-ai sourcery-ai 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.

Sorry, we are unable to review this pull request

The GitHub API does not allow us to fetch diffs exceeding 20000 lines

appflowy and others added 12 commits September 18, 2026 00:44
The add-view menu now has a "Dashboard" entry, and Playwright's substring
matchers (`hasText: 'Board'`, `getByRole` without `exact`) resolved to both
items, which failed six view-management specs in CI.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Third React best-practices review of the dashboard.

- The app rebuilds loadViewMeta (and with it navigateToView) whenever the
  trash list or the database relations change. That reached every widget's
  nested database and refetched every widget's view meta. Widgets now get
  one stable wrapper per host service that calls the latest one.
- WidgetContext carries only what its consumers read (the widget id, name,
  icon, layout, chrome flags), so a move or a resize of another widget no
  longer re-renders a widget's nested shell.
- The chart drill-down list is rebuilt once after its rows finish loading
  instead of once per loaded row (quadratic for a Number chart in Count
  mode, whose rows are not loaded before the popup opens).
- The Number chart formatters are built once.
- Losing write access leaves Edit mode during render, like a view switch.
- Dashboard imports GlobalFilterBar directly instead of through the barrel.
- Documented that "Save for everybody" writes the override as a snapshot
  (last writer wins), like every other dashboard layout write.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	src/components/database/components/settings/Layout.tsx
#	src/components/database/components/settings/__tests__/Layout.test.tsx
#	src/components/database/components/tabs/AddViewButton.tsx
#	src/components/database/components/tabs/__tests__/AddViewButton.test.tsx
#	src/components/editor/components/panels/slash-panel/SlashPanel.tsx
Vite only exposes APPFLOWY* variables from .env files to the app, and the
define for EXPERIMENTAL_DATABASE_VIEW_CREATION_ENABLED read the shell
environment only, so setting it in .env did nothing. The define now falls
back to the .env value, so a local `pnpm dev` can opt in without exporting
the variable in every shell.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o plan

The server side of the Dashboard view is merged (AppFlowy-Cloud-Premium
#1191), so the 50 feature scenarios and the 28 real-world scenarios join
the Playwright matrix as two groups. CI's release server refuses Dashboard
creation without a Pro plan, so the fixtures seed the workspace's Pro
entitlement the way the Timeline fixtures do; local debug servers skip it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fourth React best-practices review of the dashboard.

- A non-host widget resolved its source permissions only after its doc had
  loaded and its deletion probe had settled, and its nested database
  mounted read-only until then, which also held back its row prefetch: four
  serial round trips per widget. The permission resolver now wraps the
  placeholder too, so the probe runs alongside the doc load; the deletion
  probe starts from the ids; host widgets reuse the host's permissions
  instead of probing.
- The workspace database catalog (only used to name other databases in the
  global-filter editor, and refetched on every folder change) stays off
  while every widget shows the host database.
- The picker's option list is a memoized component with content-visibility,
  so a search keystroke re-renders the input alone.
- The host-service key list is checked for exhaustiveness at compile time.
- The pure global-filter field reader lives in its own module, so database
  views no longer load the per-doc observer store eagerly.
- Test fixture: the database-mount poll tolerates the bridge's reload.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Hovering a row in Edit mode shows a round ↓ at its left edge that inserts a
new row below it (the widget picker opens for the new row) and the round +
at its right edge that adds into the row, like Notion. The ↓ is disabled
with the widget-limit tooltip when the dashboard is full.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd and the widget menu

- Filters and sorts a viewer applies inside a widget in View mode stay
  local until "Save for everybody", like Notion. The widget's nested
  database gets a proxy view (view-conditions-overlay.ts) whose filters and
  sorts live in a local, unsynced Yjs doc and mirror the real view until
  the viewer changes something; DatabaseViewOverlayContext makes
  useDatabaseView() return it, so every selector, menu and dispatcher works
  unchanged. Read-only members can use widget filters and sorts
  (useConditionsReadOnly). Save for everybody writes the local copies to
  their views as one undo step; Reset drops them; the local-changes badge
  counts them.
- /dashboard in a document creates a new database whose first tab is a
  dashboard (a grid page plus a dashboard tab, like the Feed page).
- Clicking a widget's title opens its menu, as right-clicking does.
- Tests: overlay unit tests, dashboard page creation tests, header test;
  BDD scenarios for local widget filters (owner, save, read-only member),
  the slash commands (new and linked dashboard) and Change view.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- /dashboard: remove the Dashboard page too when creation fails after it
  exists (it is a sibling page of the grid under the document)
- resolve a widget's View-mode conditions overlay during render so the
  nested database mounts once with it; re-check the store after mount so a
  StrictMode simulated unmount cannot leave a destroyed overlay in place
- move the unsaved-widget count into DashboardLocalWidgetChangesContext so
  widgets stop re-rendering on every private filter edit
- DatabaseViews' advanced-mode effect reads the overlay view; the group-by
  filter cleanup writes the shared view's filters
- the widget title button takes its accessible name from the widget name
- drop the dead has-[[data-state=open]] selector on row edge controls

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Widget private conditions (View-mode overlay):
- advanced-filter selectors read the viewer's private filters
- useDatabaseView returns the overlay only for the view it targets, so the
  calendar draft's cloned doc keeps its own view
- the overlay is clean again once the private copy matches the shared view
- the overlay store is create-only while widgets render; stale overlays are
  released after commit (no provider update during render)
- "Save for everybody" skips widgets whose source database the viewer
  cannot write, and only shows when something can be saved
- the full-row prefetch counts private conditions and global filters

Global filters and charts:
- a global-filter change keeps the view's last rows until the recompute
  instead of a loading frame that unmounted rows and replayed charts
- charts show the spinner while a new filter hydrates rows
- column reorders no longer regroup chart data
- the drill-down lists and loads rows a page at a time
- the calendar draft counts private and global filters as hiding a row

Shell:
- Edit mode is derived in DashboardProvider ('auto' for an empty
  dashboard), removing the effect-driven flash on new dashboards
- rows take dashboard-wide state as props, so a commit re-renders only
  the rows that changed
- Enter in the widget picker picks from the current query

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Re-render and code-splitting fixes from the Vercel React best-practices
review of the dashboard view, plus four small correctness fixes:

- Row-height drag writes a CSS variable and a small preview store instead
  of React state per pixel; only the handle badge and the nested databases
  (deferred) follow it.
- Chart row-doc observers depend on the charted docs' identity, not the
  whole row map, so unrelated row arrivals no longer re-subscribe them.
- The global-filter editor and the widget picker body are lazy chunks with
  hover/focus preloads; viewers and published dashboards never load them.
- WidgetHeader, DashboardActions and AddSourceButton are memoized; the
  widget source takes ids instead of the widget object.
- DashboardContext is split: the rows and display settings live in a new
  DashboardLayoutContext, so the toolbar and filter bar skip layout writes.
- The catalog hook reads the store during render, the host doc is derived
  into the source map, host views are cached in the Yjs observer, and the
  view-meta app-event listeners are shared per emitter.
- Overlay rebind follows the replacement in a microtask instead of writing
  Yjs mid-render; select filters use the split-only parser; the source
  observer re-resolves the reference view when field_orders or the
  reference keys change; the picker's stale mounted ref is gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
# Conflicts:
#	src/application/constants.ts
#	src/components/database/components/settings/Layout.tsx
#	src/components/database/components/settings/__tests__/Layout.test.tsx
#	src/components/database/components/tabs/AddViewButton.tsx
#	src/components/database/components/tabs/__tests__/AddViewButton.test.tsx
# Conflicts:
#	playwright/e2e/database/chart-aggregation.spec.ts
#	playwright/e2e/database/chart-chart-type.spec.ts
#	playwright/e2e/database/chart-date-axis.spec.ts
#	playwright/e2e/database/chart-drilldown.spec.ts
#	playwright/e2e/database/chart-persistence.spec.ts
#	playwright/e2e/database/chart-toggles.spec.ts
#	playwright/e2e/database/chart-y-field.spec.ts
#	playwright/support/chart-test-helpers.ts
#	playwright/support/row-detail-helpers.ts
#	playwright/support/selectors.ts
#	playwright/support/subscription-test-helpers.ts
#	src/@types/translations/en.json
#	src/application/database-blob/index.ts
#	src/application/database-yjs/__tests__/configuration-history.test.tsx
#	src/application/database-yjs/__tests__/database-view-duplicate.test.ts
#	src/application/database-yjs/__tests__/useAddDatabaseView.test.tsx
#	src/application/database-yjs/__tests__/useRowOrdersSelector.test.tsx
#	src/application/database-yjs/__tests__/useRowsByGroup.test.tsx
#	src/application/database-yjs/chart.type.ts
#	src/application/database-yjs/context.ts
#	src/application/database-yjs/dispatch.ts
#	src/application/database-yjs/history.ts
#	src/application/database-yjs/selector.ts
#	src/application/services/js-services/http/page-api.ts
#	src/application/types.ts
#	src/application/view-loader/index.ts
#	src/assets/icons/center_peek.svg
#	src/assets/icons/full_page.svg
#	src/assets/icons/side_peek.svg
#	src/components/app/settings/AccountAppPanel.tsx
#	src/components/database/Database.tsx
#	src/components/database/DatabaseRowModal.tsx
#	src/components/database/chart/Chart.tsx
#	src/components/database/chart/ChartProvider.tsx
#	src/components/database/chart/ChartRowListPopup.tsx
#	src/components/database/chart/hooks/index.ts
#	src/components/database/chart/hooks/useChartData.test.tsx
#	src/components/database/chart/hooks/useChartData.ts
#	src/components/database/chart/useChartContext.ts
#	src/components/database/chart/widgets/BarChart.tsx
#	src/components/database/chart/widgets/ChartTooltip.tsx
#	src/components/database/chart/widgets/DonutChart.tsx
#	src/components/database/chart/widgets/HorizontalBarChart.tsx
#	src/components/database/chart/widgets/LineChart.tsx
#	src/components/database/chart/widgets/__tests__/BarChart.test.tsx
#	src/components/database/chart/widgets/__tests__/ChartTooltip.test.tsx
#	src/components/database/chart/widgets/__tests__/DonutChart.test.tsx
#	src/components/database/chart/widgets/__tests__/HorizontalBarChart.test.tsx
#	src/components/database/chart/widgets/__tests__/LineChart.test.tsx
#	src/components/database/chart/widgets/chartUtils.ts
#	src/components/database/chart/widgets/index.ts
#	src/components/database/components/board/column/ColumnHeaderPrimitive.tsx
#	src/components/database/components/board/drag-and-drop/useColumnsDrag.ts
#	src/components/database/components/board/group/Columns.tsx
#	src/components/database/components/board/group/Group.tsx
#	src/components/database/components/grid/controls/RowMenu.tsx
#	src/components/database/components/grid/grid-cell/GridRowCell.tsx
#	src/components/database/components/grid/grid-group/GridGroupHeader.tsx
#	src/components/database/components/grid/grid-row/GridNewRow.tsx
#	src/components/database/components/grid/grid-row/GridVirtualRow.tsx
#	src/components/database/components/grid/grid-table/GridVirtualizer.tsx
#	src/components/database/components/grid/grid-table/useGridDnd.ts
#	src/components/database/components/grid/grid-table/useGridVirtualizer.ts
#	src/components/database/components/settings/ChartLayoutSettings.tsx
#	src/components/database/components/settings/ChartSettings.tsx
#	src/components/database/components/settings/GridSettings.tsx
#	src/components/database/components/settings/TimelineSettings.tsx
#	src/components/database/components/tabs/DatabaseTabs.tsx
#	src/components/database/grid/useGridContext.ts
#	src/components/database/layout.ts
#	src/components/database/list/ListGroup.tsx
#	src/components/database/timeline/TimelineView.tsx
#	src/components/editor/components/blocks/database/hooks/__tests__/useDocumentLoader.test.ts
#	src/components/editor/components/blocks/database/hooks/useDocumentLoader.ts
#	src/components/editor/components/panels/slash-panel/SlashPanel.tsx
#	src/components/editor/components/panels/slash-panel/__tests__/SlashPanel.creation.test.tsx
#	src/components/editor/components/toolbar/block-controls/ControlsMenu.tsx
#	src/utils/billing-error.ts
# Conflicts:
#	src/application/database-yjs/dispatch.ts
#	src/application/database-yjs/fields/date/date.type.ts
#	src/application/database-yjs/fields/date/relativeDate.ts
#	src/application/database-yjs/filter.ts
#	src/application/database-yjs/hooks/useBackgroundRowDocLoader.ts
#	src/application/database-yjs/hooks/useRelativeDateFilterRefresh.ts
#	src/application/database-yjs/selector.ts
#	src/components/database/Database.tsx
#	src/components/database/DatabaseViews.tsx
#	src/components/database/components/board/group/Group.tsx
#	src/components/database/components/filters/advanced/AdvancedDateFilterValueInput.tsx
#	src/components/database/components/filters/advanced/FilterControls.tsx
#	src/components/database/components/filters/filter-menu/DateTimeFilterDatePicker.tsx
#	src/components/database/components/filters/filter-menu/DateTimeFilterMenu.tsx
#	src/components/database/components/filters/filter-menu/DateTimeFilterStartEndDateSelect.tsx
#	src/components/database/components/filters/filter-menu/FilterConditionsSelect.tsx
#	src/components/database/components/filters/filter-menu/RollupFilterControls.tsx
#	src/components/database/components/filters/overview/useFilterChipLabel.ts
#	src/components/database/components/settings/GallerySettings.tsx
#	src/components/database/components/settings/Layout.tsx
#	src/components/database/list/ListGroup.tsx
Remove widget-count and row-size caps while preserving saved rows and widths.
Accept legacy advanced chart aggregations and synchronize parity fixtures.
Use clicked rows for text and URL groups whose trimmed or normalized
values cannot be represented by ordinary text filters. Synchronize the
shared fixture with Desktop without changing existing local fix contents.
Dashboard loading scenarios failed during fixture setup with legacy field
creation errors and linked-view admission contention.

Seed fields with one immutable CRDT update and create views atomically.
Retry explicit backpressure with the same IDs and payload, require a
durable acknowledgement, and verify fields before creating fixture rows.
Cover duplicate delivery, bounded retries, and ambiguous failures.
A newly created document can appear while the global visible-page count
stays unchanged as lazy sidebar contents change. Follow the atomic
creation receipt's view ID through creation, rename, and deletion.

Wait for the created preview to finish hydration before closing it with
its current control, instead of racing its activation with old selectors.
Suspend unfinished cold widgets before reusing their loading slots.
Keep cached views mounted and ignore reports from abandoned loads.

Share cancellation ownership for database documents and abort unfinished
blob walks after their last view leaves. Preserve shared readers and
required persistence work.

Cover 100-widget scrolling, rapid returns, cache reuse, and HTTP aborts.
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