blixify-ui-web-mcp 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/lib/components/action/iconButton/iconButton.stories.tsx +11 -2
  2. package/lib/components/auth/signUp/signUp.stories.tsx +39 -1
  3. package/lib/components/chart/statsCard/README.md +24 -0
  4. package/lib/components/chart/statsCard/statsCard.stories.tsx +68 -0
  5. package/lib/components/chat/chatBase/chatBase.stories.tsx +1 -1
  6. package/lib/components/data/dataGraph/dataGraph.stories.tsx +5 -5
  7. package/lib/components/data/dataTemplate/README.md +204 -85
  8. package/lib/components/data/dataTemplate/dataTemplate.stories.tsx +307 -295
  9. package/lib/components/data/dataTemplate/drive.stories.tsx +197 -0
  10. package/lib/components/data/dataWrapper/README.md +109 -22
  11. package/lib/components/data/dataWrapper/dataWrapper.bareHooks.stories.tsx +951 -0
  12. package/lib/components/data/dataWrapper/dataWrapper.edit.stories.tsx +356 -5
  13. package/lib/components/data/dataWrapper/dataWrapper.view.stories.tsx +79 -5
  14. package/lib/components/display/calendar/calendar.stories.tsx +1 -1
  15. package/lib/components/display/detailList/README.md +11 -10
  16. package/lib/components/display/detailList/detailList.stories.tsx +16 -3
  17. package/lib/components/display/feeds/README.md +3 -3
  18. package/lib/components/display/feeds/feeds.stories.tsx +3 -3
  19. package/lib/components/display/filePreview/filePreview.stories.tsx +111 -0
  20. package/lib/components/display/modal/README.md +3 -0
  21. package/lib/components/display/modal/modal.stories.tsx +50 -1
  22. package/lib/components/display/newCalendar/README.md +0 -6
  23. package/lib/components/display/newCalendar/newCalendar.stories.tsx +1 -1
  24. package/lib/components/display/newFeeds/README.md +1 -5
  25. package/lib/components/display/newFeeds/newFeeds.stories.tsx +3 -3
  26. package/lib/components/display/newKanban/README.md +0 -7
  27. package/lib/components/display/newList/README.md +1 -4
  28. package/lib/components/display/newTable/README.md +29 -9
  29. package/lib/components/display/newTable/newTable.stories.tsx +120 -9
  30. package/lib/components/display/tag/README.md +1 -1
  31. package/lib/components/display/tag/tag.stories.tsx +7 -0
  32. package/lib/components/input/markdown/markdown.stories.tsx +3 -1
  33. package/lib/components/input/uploadInput/uploadInput.stories.tsx +41 -0
  34. package/lib/components/navigation/leftNav/leftNav.stories.tsx +175 -0
  35. package/lib/components/navigation/tabs/tabs.stories.tsx +23 -0
  36. package/lib/components/template/calendarView/calendarView.stories.tsx +4 -4
  37. package/lib/components/template/chatDashboard/chatDashboard.stories.tsx +2 -2
  38. package/lib/mcp/tools/getBackendComponent.d.ts.map +1 -1
  39. package/lib/mcp/tools/getBackendComponent.js +7 -3
  40. package/lib/mcp/tools/getBackendComponent.js.map +1 -1
  41. package/lib/mcp/tools/suggestTemplate.js +3 -3
  42. package/lib/mcp/tools/suggestTemplate.js.map +1 -1
  43. package/package.json +1 -1
  44. package/lib/components/data/dataTemplate/dataModule.stories.tsx +0 -191
  45. package/lib/components/data/dataWrapper/dataWrapper.consumer.stories.tsx +0 -2125
  46. package/lib/components/data/dataWrapper/dataWrapper.utils.stories.tsx +0 -576
  47. package/lib/components/data/flexFilter/flexFilter.stories.tsx +0 -171
@@ -106,10 +106,10 @@ Tab (DataStructure.tabId) ← tab bar across the top of the read
106
106
  untouched tab costs no request. Without it every save writes the full record and toasts,
107
107
  changed or not.
108
108
  The API behind the collection must accept a partial document (an upsert by id that
109
- `$set`s only the sent fields) — Verdant's `mongoData` route does; check before turning it
109
+ `$set`s only the sent fields) — a `mongoData`-style upsert route does; check before turning it
110
110
  on elsewhere.
111
111
 
112
- **Offline mode** (`bareOffline`, the Meraque work-order checklist pattern)
112
+ **Offline mode** (`bareOffline`, the offline work-order checklist pattern)
113
113
 
114
114
  ```
115
115
  mount (online) ─▶ prefetch latest N docs + bareOfflineReferences ─▶ IndexedDB store "local"
@@ -121,14 +121,15 @@ ref.handleUploadOfflineData() ─▶ every pending doc → server (diffed agains
121
121
  ```
122
122
 
123
123
  - The DTW does the prefetch, the local reads, the local writes and the upload; the app owns the
124
- _policy_: when to go offline, when to sync, what to tell the user. Meraque keeps an `offline`
124
+ _policy_: when to go offline, when to sync, what to tell the user. A typical app keeps an `offline`
125
125
  state, shows a banner ("Going offline? Sync data required…" / "You're in offline mode." /
126
126
  "Data synced. Ready for offline."), passes `bareOffline: offline`, and calls
127
127
  `dtwRef.current.handleUploadOfflineData()` when the connection is back.
128
128
  - Prefetch never overwrites pending local edits — pending docs win over the server copy of the
129
129
  same id. Reference collections listed in `bareOfflineReferences` are what make reference
130
130
  fields (team, pilot, robot…) selectable with no network.
131
- - Story: `Data / Data Wrapper / Consumer Fixtures / Meraque · Work Order (Offline)` — prefetch,
131
+ - Story: the offline work-order fixture under `Data / Data Wrapper / Consumer Fixtures`, in the local
132
+ Storybook only (client fixtures are not shipped in the MCP package) — prefetch,
132
133
  an offline toggle, an offline save and Sync now, all mocked in the page.
133
134
  - This is a feature, not a test harness — stories fake the server with `axios-mock-adapter`
134
135
  instead (see the Consumer Fixtures file).
@@ -139,7 +140,7 @@ just its label — text, textarea, select and its dropdown, date, checkbox and r
139
140
  the read view's cards, modals, the drawer, toasts and the floating action bar. Pass
140
141
  `organise.darkModeBg` with the class your page already uses (`"bg-neutral-900"`) and those
141
142
  surfaces adopt it; without it they fall back to `bg-gray-900`. Story: `Consumer Fixtures /
142
- Dark Mode` (Sales Leads list + KPJ form on a Meraque-style page).
143
+ Dark Mode` (a sales-leads list and a long grant form on a black page).
143
144
 
144
145
  **Wide tables** — every table scrolls inside a `ScrollShadow`: a soft fade on the edge
145
146
  that still hides columns, gone at the end of the scroll, over a thin always-visible
@@ -175,9 +176,9 @@ update form only, the light `bg-primary-50` tint behind a collapsible section. R
175
176
  section cards are plain white. Per-value colour exists only on `list` / `multipleList`
176
177
  columns via `listSelectionColour`.
177
178
 
178
- A worked example is Blixify Space's KPJ **Projects** space: every column carries a lettered
179
- `tabId` (`A. Research Identification` … `P. Applicant Endorsement`) plus a `groupId`
180
- (`Research Details`, `Application Details`, …), and its `kpjuResearchers` listObject shows
179
+ A worked example is a long grant-application space: every column carries a lettered
180
+ `tabId` (`A. Overview` … `P. Endorsement`) plus a `groupId`
181
+ (`Details`, `Application`, …), and a `researchers` listObject shows
181
182
  as a nested table inside the _Applicants' Details_ section.
182
183
 
183
184
  ## View Settings
@@ -348,7 +349,9 @@ No `edit` prop — hides all create/update/delete controls. Users can browse and
348
349
 
349
350
  ### Full CRUD
350
351
 
351
- Enable all editing features. `allEditable` turns on create, update, and delete in one flag.
352
+ Enable all editing features. `allEditable` turns on create and update; delete is
353
+ granted separately by `deleteBtn`, and inline cell editing by `listEditable` —
354
+ see the Write permission matrix below.
352
355
 
353
356
  ```tsx
354
357
  <DataTemplate
@@ -560,6 +563,58 @@ Set `viewType="kanban"` on an `extendedTabs` entry and configure `kanbanSettings
560
563
 
561
564
  ---
562
565
 
566
+ ### Drive view
567
+
568
+ A Google Drive-style folder browser. Every row in the collection is a file or a folder, so a folder is a row, and moving something only changes one column. Set `viewType="drive"` on an `extendedTabs` entry and name the four columns in `driveSettings`.
569
+
570
+ - **Browse:** the open folder's rows load as one unpaged list, with folders first and then files, sorted A–Z. A path above the list goes back up. While the DTW search has text, the view searches the whole drive and shows each result's folder.
571
+ - **Folder id:** pass `organise.folderId` and `organise.onChangeFolder` to keep the open folder in the url. Without them the view keeps its own state.
572
+ - **Actions:** New folder, and Upload (one row per file, stored in that row's own storage folder). Files dragged over the drive show a "Drop to upload to <folder>" overlay, and a drop starts uploading straight away. The record Create button is hidden on a drive tab. Each item's menu has Details (the record's read view), Rename, Move to… and Delete. Deleting a folder deletes everything inside it, rows and storage.
573
+ - **Permissions:** `allEditable` or `createBtn` shows New folder and Upload. `canUpdateRecord` or `canInlineUpdate` allows Rename and Move. `deleteBtn` allows Delete. Without them the drive can be browsed but not changed.
574
+ - **Layout:** grid or list. The choice is remembered per browser, and phones start in the list layout.
575
+
576
+ ```tsx
577
+ <DataTemplate
578
+ title="Documents"
579
+ description=""
580
+ type="list"
581
+ collectionId="documents"
582
+ model={[
583
+ { id: "name", name: "Name", type: "string" },
584
+ { id: "kind", name: "Kind", type: "list", listSelection: ["folder", "file"] },
585
+ { id: "parentId", name: "Folder", type: "string" },
586
+ { id: "file", name: "File", type: "multipleFile" },
587
+ { id: "size", name: "Size", type: "number" },
588
+ ]}
589
+ localURLEndpoint=""
590
+ devSettings={devSettings}
591
+ lib={{ axios, Menu, Transition }}
592
+ edit={{ allEditable: true, listEditable: true, deleteBtn: true }}
593
+ organise={{
594
+ handleNavigate,
595
+ folderId,
596
+ onChangeFolder: setFolderId,
597
+ extendedTabs: [
598
+ {
599
+ name: "Drive",
600
+ type: "list",
601
+ viewType: "drive",
602
+ defaultTab: true,
603
+ driveSettings: {
604
+ nameColumnId: "name",
605
+ kindColumnId: "kind",
606
+ parentColumnId: "parentId",
607
+ fileColumnId: "file",
608
+ sizeColumnId: "size",
609
+ },
610
+ },
611
+ ],
612
+ }}
613
+ />
614
+ ```
615
+
616
+ ---
617
+
563
618
  ### With search and filter
564
619
 
565
620
  Use `organise.additionalQuery` to add filter controls above the list. Each entry maps to a filter UI control.
@@ -766,17 +821,19 @@ const devSettings = parseWorkspaceSettings(
766
821
 
767
822
  ### Ref Methods
768
823
 
769
- | Method | Description |
770
- | ---------------------------------- | ----------------------------------------------------------------- |
771
- | `handleRefresh()` | Re-fetches the current list data, resetting pagination to page 1 |
772
- | `handleRefreshCurrentPage()` | Re-fetches in place, keeping page index, cursor, and filters |
773
- | `handleFormSubmit()` | Programmatically submits the update/create form |
774
- | `handleFormCheck()` | Validates the form without submitting |
775
- | `handlePopUpModal()` | Opens the create/update modal |
776
- | `handleDeleteModal()` | Opens the delete confirmation modal |
777
- | `handleUpdateSelectedData(fields)` | Prefills form fields. `fields` is `{ key: string; value: any }[]` |
778
- | `handleExportReadPDF()` | Triggers a PDF export of the current read view |
779
- | `handleUploadOfflineData()` | Uploads any locally cached offline data |
824
+ | Method | Description |
825
+ | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
826
+ | `handleRefresh()` | Re-fetches the current list data, resetting pagination to page 1 |
827
+ | `handleRefreshCurrentPage()` | Re-fetches in place, keeping page index, cursor, and filters |
828
+ | `handleFormSubmit()` | Programmatically submits the update/create form |
829
+ | `handleFormCheck()` | Validates the form without submitting |
830
+ | `handlePopUpModal()` | Opens the create/update modal |
831
+ | `handleDeleteModal()` | Opens the delete confirmation modal |
832
+ | `handleUpdateSelectedData(fields)` | Prefills form fields. `fields` is `{ key: string; value: any }[]` |
833
+ | `handleExportReadPDF()` | Triggers a PDF export of the current read view |
834
+ | `handleUploadOfflineData()` | Uploads any locally cached offline data |
835
+ | `handleApplyFlexFilters(filters)` | Applies flex filters, merged by `columnId` (incoming replaces same-column rows; others preserved). `filters` is `FlexFilterData[]`. Requires `bareFlexFilters` |
836
+ | `handleClearFlexFilters(columnIds?)` | Clears flex filters by `columnId` (others preserved), or all when called with no args. Requires `bareFlexFilters` |
780
837
 
781
838
  ### Required props
782
839
 
@@ -855,17 +912,54 @@ const devSettings = parseWorkspaceSettings(
855
912
 
856
913
  | Name | Type | Description |
857
914
  | ----------------------- | ------------- | -------------------------------------------------------- |
858
- | `allEditable` | `boolean` | Enables add, update, and delete |
915
+ | `allEditable` | `boolean` | Enables add and update, and gates card drag and batch writes |
859
916
  | `listAddable` | `boolean` | Enables adding rows inline in list view |
860
- | `listEditable` | `boolean` | Enables inline cell editing in list view |
917
+ | `listEditable` | `boolean` | Enables inline cell editing in list view, and gates its write |
861
918
  | `createBtn` | `boolean` | Shows a create button even when `allEditable` is `false` |
862
- | `deleteBtn` | `boolean` | Enables delete and batch delete |
919
+ | `deleteBtn` | `boolean` | Enables delete and batch delete, independent of `allEditable` |
863
920
  | `disabledUpdate` | `boolean` | Disables update and batch update |
864
921
  | `disableBatchUpdate` | `boolean` | Disables batch update only |
865
922
  | `enableUpdateDraft` | `boolean` | Enables save-as-draft on the update form |
866
923
  | `disabledTabsDeleteBtn` | `boolean` | Disables the delete button inside extended tabs |
867
924
  | `activityLog` | `ActivityLog` | See ActivityLog below |
868
925
 
926
+ #### Write permission matrix
927
+
928
+ These rules decide whether a control is **rendered**. The inline cell, Kanban
929
+ drag, Kanban checkbox and batch callbacks re-check them before writing, so a
930
+ stray callback cannot write. Delete is render-gated only, because the delete
931
+ modal is also opened through the imperative `handleDeleteModal`.
932
+
933
+ | Control | Requires |
934
+ | -------------------------------------------------- | --------------------------------------- |
935
+ | Kanban drag/drop and its update write | `allEditable && !disabledUpdate` |
936
+ | Inline cell edit and its write | `listEditable && !disabledUpdate` |
937
+ | Kanban boolean checkbox and its write | `listEditable && !disabledUpdate` |
938
+ | Read-view Update button | `allEditable && !disabledUpdate` |
939
+ | List Update column | `allEditable && !disabledUpdate`, or `bareListMultipleSelectAddtionalActions` |
940
+ | Batch update, clone, change-to-draft | `allEditable && !disabledUpdate && !disableBatchUpdate` (the batch Update button also requires a non-Firebase backend) |
941
+ | Delete button, batch delete, map delete | `deleteBtn` (independent of `allEditable`) |
942
+ | Map polygon select | batch-update or delete permission |
943
+
944
+ > `deleteBtn` no longer requires `allEditable`. An `edit` of
945
+ > `{ allEditable: false, deleteBtn: true }` renders Delete in the read and update
946
+ > action bars, where it was previously hidden. Grant `deleteBtn` per role rather
947
+ > than unconditionally.
948
+
949
+ The imperative API is **not** gated by these rules. `handleFormSubmit`,
950
+ `handleFormSaveDraft`, `handleDeleteModal` and `handleUploadOfflineData` are only
951
+ reachable from consumer code, and `DataTemplateWrapper` defaults `edit` to
952
+ `disabledUpdate: true, deleteBtn: false` — gating them would break every consumer
953
+ that drives its own form without passing an `edit` prop. Neither is the shared
954
+ write path (`handleSubmitData`), which also serves the auth modal writing a
955
+ changed email back to the profile record. A consumer that does not want a write
956
+ path should not render it.
957
+
958
+ > Reading these rules through `DataTemplateWrapper`: it spreads your `edit` over
959
+ > its own defaults, so `edit={{ allEditable: true }}` still inherits
960
+ > `disabledUpdate: true` and yields no update affordances. Pass
961
+ > `disabledUpdate: false` explicitly to enable update, drag and batch controls.
962
+
869
963
  #### Inline editability matrix (`listEditable`)
870
964
 
871
965
  Which field types can be edited from the list table, and how. Types not listed under
@@ -941,7 +1035,8 @@ Which field types can be edited from the list table, and how. Types not listed u
941
1035
  | `fixedPagination` | `boolean` | Fixes the pagination bar to the bottom of the viewport |
942
1036
  | `filterComponentNewRow` | `boolean` | Renders each filter component on its own row |
943
1037
  | `addColumnEnabled` | `boolean` | Shows an add-column button in the table header |
944
- | `persistViewState` | `"session" \| "local"` | Remembers the list's sort, filters, hidden columns, page and search in `sessionStorage` / `localStorage` per collection, so a Back navigation lands where the user left |
1038
+ | `persistViewState` | `"persistent" \| "session"` | Remembers the list's sort, filters, hidden columns, page and search per collection, so a Back navigation lands where the user left. `"persistent"` uses `localStorage`; `"session"` writes `sessionStorage` and reads it first, falling back to `localStorage`. List view only |
1039
+ | `persistKey` | `string` | Keeps a separate saved view state for this instance: the storage key becomes `blixify-dtw-persist-<collectionId>-<persistKey>`. Saved state is read once, on mount, so give the component a React `key` that changes with `persistKey` |
945
1040
  | `groupBy` | `string` | Column ID to group list results by |
946
1041
  | `groupIdCollapsible` | `{ [key: string]: boolean }` | Initial collapsed/expanded state per group ID |
947
1042
  | `sortGroupByAlphabetically` | `boolean` | Sorts group-by values alphabetically |
@@ -1015,62 +1110,65 @@ Which field types can be edited from the list table, and how. Types not listed u
1015
1110
 
1016
1111
  Injects custom React components and callbacks into the list, read, and update views.
1017
1112
 
1018
- | Name | Type | Description |
1019
- | ---------------------------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1020
- | `bareViewSettings` | `boolean` | Turns on the view settings feature — the panel (columns hide / reorder / search, sort, rows per page) and the hide, drag and sort controls in the table header. Always on under `bareNewDTW` |
1021
- | `bareReadComponent` | `(data: any) => any` | Custom component rendered in read view |
1022
- | `bareReadComponentPos` | `"top"` | Renders `bareReadComponent` above the default read content |
1023
- | `bareReadComponentHide` | `boolean` | Hides the default read content (shows only `bareReadComponent`) |
1024
- | `bareReadReferenceView` | `(dataId, collectionId, attributeId) => boolean \| void` | Controls whether a reference field opens a view |
1025
- | `bareReadDescription` | `(key: string, value: any) => any` | Custom renderer for read view field values |
1026
- | `bareReadHandleData` | `(data: any) => void` | Called when read view data is loaded |
1027
- | `bareReadListTabs` | `boolean` | Shows list-style tabs in read view |
1028
- | `bareListComponent` | `(data, prettierData, loading, pageIndex) => any` | Fully replaces the list UI with a custom component |
1029
- | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons rendered on each list row |
1030
- | `bareListMultipleSelectAddtionalActions` | `{ text: string; className?: string; onClick: (ids, selectAll, query) => void }[]` | Extra bulk-action buttons shown when rows are selected |
1031
- | `bareListGridComponent` | `(data: any) => any` | Custom card renderer for grid view |
1032
- | `bareListGridColClassName` | `string` | Tailwind class for grid column width |
1033
- | `bareListGridTags` | `(data: any) => string[]` | Returns tag strings shown on grid cards |
1034
- | `bareListGridFallbackImg` | `(data: any) => string \| ReactElement` | Fallback image/element for grid cards without an image |
1035
- | `bareListGridRibbonText` | `(data: any) => string` | Text shown as a ribbon on grid cards |
1036
- | `bareListHandleData` | `(data, prettierData) => void` | Called when list data is loaded |
1037
- | `bareListHandleSelection` | `(selectAll, selectedIds, query?) => void` | Called when row selection changes |
1038
- | `bareListHandleFilter` | `(search, select, date, reference) => void` | Called when any filter changes |
1039
- | `bareListFilterSelected` | `(filterSearchParams, filterSelection, filterReference, filterReferenceDate) => void` | Called with the current filter state whenever it changes |
1040
- | `bareListDescription` | `(key: string, value: any) => any` | Custom renderer for list view field values |
1041
- | `bareListFilterQuery` | `Query[]` | Additional queries always applied to list fetches |
1042
- | `bareListFilterAddComponent` | `ReactElement[]` | Extra filter components rendered in the filter bar |
1043
- | `bareListPipeline` | `PipeLine[]` | Additional pipeline stages appended to list queries |
1044
- | `bareListObjectHandleData` | `(type: "read" \| "update" \| "new", data: any) => void` | Called when a list-object row is opened |
1045
- | `bareUpdatePrefill` | `(data: any) => { key: string; value: any }[]` | Returns prefill values for the update form based on existing data |
1046
- | `bareUpdateComponent` | `(data: any) => any` | Custom component rendered inside the update form |
1047
- | `bareUpdateComponentAbove` | `boolean` | Renders `bareUpdateComponent` above the default form fields |
1048
- | `bareSaveOnTabChange` | `boolean` | Auto-save: every Next / Previous on a tabbed update form writes a draft first, silently (no toast). Pair with `edit.enableUpdateDraft` |
1049
- | `bareUpsertPartialUpdate` | `boolean` | Upsert by `props.id` and send only the fields that changed since load; a save with no changes skips the write. Makes auto-save safe across devices |
1050
- | `bareUpdateActionComponent` | `(data: any, formRef?: any) => any` | Custom action buttons rendered in the update form footer |
1051
- | `bareFlexFilters` | `boolean` | Funnel icon opens the Filters builder (column · condition · value, values from the schema) — replaces hand-rolled page filters; new table only |
1052
- | `bareListFilterAsPopup` | `boolean` | Shows the list's filter inputs in a popup instead of the header row |
1053
- | `bareListTablePinColumns` | `{ left?: string[]; right?: string[] }` | Columns kept sticky at the edges while the table scrolls sideways (`"update"` is the actions column); new table only |
1054
- | `bareListMobileView` | `boolean` | Phone card list instead of the table (the app passes its own isMobile) |
1055
- | `bareListMobileFloatingSearch` | `boolean` | Floating search bar at the bottom on phones; the list reserves room under its last row for it |
1056
- | `bareListMaxSelectedCount` | `number` | Caps how many rows the checkbox column may select at once |
1057
- | `bareUpdateHandleData` | `(data: any, changedAttributeIds?: string[]) => void` | Called on every form field change with the current data and changed field IDs |
1058
- | `bareUpdateHandlePreComplete` | `(data: any) => Promise<boolean>` | Called before save — return `false` to cancel |
1059
- | `bareUpdateHandleComplete` | `(data: any) => Promise<any>` | Called after save completes |
1060
- | `bareUpdateHandlePostComplete` | `(data: any) => Promise<any>` | Called after post-save operations complete |
1061
- | `bareUpdateColumnType` | `"one" \| "two" \| "four"` | Form column layout: `"one"` = 2-col grid, `"two"` = 4-col grid (default), `"four"` = 4-col grid |
1062
- | `bareUpdateTabComponent` | `(tabIds: string[]) => { tabId: string; icon?: ReactElement; skip?: boolean }[]` | Custom icons/skip flags for form tabs |
1063
- | `bareUpdateActionBottom` | `boolean` | Plain right-aligned action row instead of the floating pill — for short forms inside a `Modal` |
1064
- | `bareUpdateTabId` | `(tabId: string) => void` | Called when the active form tab changes |
1065
- | `bareUpdateIndividualComponent` | `(columnId, ref, selectedData, setSelectedData) => ReactElement \| null` | Replaces a specific form field with a custom component |
1066
- | `bareUpdateMobileView` | `boolean` | Renders the update form in mobile-optimised layout |
1067
- | `bareOffline` | `boolean` | Enables offline data caching via IndexedDB |
1068
- | `bareOfflineNetworkListener` | `boolean` | With `bareOffline`: follow `navigator.onLine` — saves go to the server while online and to IndexedDB only when the network is down. Without it every save goes to IndexedDB until `handleUploadOfflineData()` |
1069
- | `bareOfflinePrefetchLimit` | `number` | With `bareOffline`: how many of the collection's latest docs to download into IndexedDB on mount (default 10) |
1070
- | `bareOfflineReferences` | `Array<{ collectionId: string; limit?: number }>` | With `bareOffline`: reference collections to download on mount so reference dropdowns keep working offline |
1071
- | `bareCSVImportEndpoint` | `string` | Custom CSV import endpoint |
1072
- | `bareCSVExportEndpoint` | `string` | Custom CSV export endpoint |
1073
- | `bareHideTableExtraMultipleAction` | `boolean` | Hides the extra multiple-action button in table view |
1113
+ | Name | Type | Description |
1114
+ | ---------------------------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1115
+ | `bareViewSettings` | `boolean` | Turns on the view settings feature — the panel (columns hide / reorder / search, sort, rows per page) and the hide, drag and sort controls in the table header. Always on under `bareNewDTW` |
1116
+ | `bareReadComponent` | `(data: any, rawData?: any) => any` | Custom component rendered in read view. `data` is display data (labels + elements); `rawData` is the untouched DB doc |
1117
+ | `bareReadComponentPos` | `"top"` | Renders `bareReadComponent` above the default read content |
1118
+ | `bareReadComponentHide` | `boolean` | Hides the default read content (shows only `bareReadComponent`) |
1119
+ | `bareReadReferenceView` | `(dataId, collectionId, attributeId) => boolean \| void` | Controls whether a reference field opens a view |
1120
+ | `bareReadDescription` | `(key: string, value: any) => any` | Custom renderer for read view field values |
1121
+ | `bareReadHandleData` | `(data: any, rawData?: any) => void` | Called when read view data is loaded. `data` is display data (labels + elements); `rawData` is the untouched DB doc |
1122
+ | `bareReadListTabs` | `boolean` | Shows list-style tabs in read view |
1123
+ | `bareListComponent` | `(data, prettierData, loading, pageIndex) => any` | Fully replaces the list UI with a custom component |
1124
+ | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons rendered on each list row |
1125
+ | `bareListMultipleSelectAddtionalActions` | `{ text: string; className?: string; onClick: (ids, selectAll, query) => void }[]` | Extra bulk-action buttons shown when rows are selected |
1126
+ | `bareListGridComponent` | `(data: any) => any` | Custom card renderer for grid view |
1127
+ | `bareListGridColClassName` | `string` | Tailwind class for grid column width |
1128
+ | `bareListGridTags` | `(data: any) => string[]` | Returns tag strings shown on grid cards |
1129
+ | `bareListGridFallbackImg` | `(data: any) => string \| ReactElement` | Fallback image/element for grid cards without an image |
1130
+ | `bareListGridRibbonText` | `(data: any) => string` | Text shown as a ribbon on grid cards |
1131
+ | `bareListHandleData` | `(data, prettierData) => void` | Called when list data is loaded |
1132
+ | `bareListHandleSelection` | `(selectAll, selectedIds, query?) => void` | Called when row selection changes |
1133
+ | `bareListHandleFilter` | `(search, select, date, reference) => void` | Called when any filter changes |
1134
+ | `bareListFilterSelected` | `(filterSearchParams, filterSelection, filterReference, filterReferenceDate) => void` | Called with the current filter state whenever it changes |
1135
+ | `bareListDescription` | `(key: string, value: any) => any` | Custom renderer for list view field values |
1136
+ | `bareListFilterQuery` | `Query[]` | Additional queries always applied to list fetches |
1137
+ | `bareListFilterAddComponent` | `ReactElement[]` | Extra filter components rendered in the filter bar |
1138
+ | `bareListPipeline` | `PipeLine[]` | Additional pipeline stages appended to list queries |
1139
+ | `bareListObjectHandleData` | `(type: "read" \| "update" \| "new", data: any) => void` | Called when a list-object row is opened |
1140
+ | `bareUpdatePrefill` | `(data: any) => { key: string; value: any }[]` | Returns prefill values for the update form based on existing data |
1141
+ | `bareUpdateComponent` | `(data: any) => any` | Custom component rendered inside the update form |
1142
+ | `bareUpdateComponentAbove` | `boolean` | Renders `bareUpdateComponent` above the default form fields |
1143
+ | `bareSaveOnTabChange` | `boolean` | Auto-save: every Next / Previous on a tabbed update form writes a draft first, silently (no toast). Pair with `edit.enableUpdateDraft` |
1144
+ | `bareUpsertPartialUpdate` | `boolean` | Upsert by `props.id` and send only the fields that changed since load; a save with no changes skips the write. Makes auto-save safe across devices |
1145
+ | `bareUpdateActionComponent` | `(data: any, formRef?: any) => any` | Custom action buttons rendered in the update form footer |
1146
+ | `bareFlexFilters` | `boolean` | Funnel icon opens the Filters builder (column · condition · value, values from the schema) — replaces hand-rolled page filters; new table only |
1147
+ | `bareOnFlexFiltersChange` | `(flexFilters: FlexFilterData[]) => void` | Fires when the applied (debounced) flex filters change — from user panel edits or programmatic `handleApplyFlexFilters` / `handleClearFlexFilters`. Lets a parent observe live filter state. Needs `bareFlexFilters` |
1148
+ | `bareListFilterAsPopup` | `boolean` | Shows the list's filter inputs in a popup instead of the header row |
1149
+ | `bareListTablePinColumns` | `{ left?: string[]; right?: string[] }` | Columns kept sticky at the edges while the table scrolls sideways (`"update"` is the actions column); new table only |
1150
+ | `bareListMobileView` | `boolean` | Phone card list instead of the table (the app passes its own isMobile) |
1151
+ | `bareListMobileFloatingSearch` | `boolean` | Floating search bar at the bottom on phones; the list reserves room under its last row for it |
1152
+ | `bareMobileTooltip` | `MobileViewTooltip` | Passed to NewTable as `mobileTooltip` when `bareNewDTW` and `bareListMobileView` are on: a Tag, trailing text and summary line on the collapsed row, plus a hover card. See the NewTable README → Mobile tooltip |
1153
+ | `bareListMobileTooltip` | `NewListMobileTooltip` | Passed to NewList when `bareNewDTW` is on: `imageKey`, `summaryKeys`, `tagKeys` and `tagColors` for the hover card on list items |
1154
+ | `bareListMaxSelectedCount` | `number` | Caps how many rows the checkbox column may select at once |
1155
+ | `bareUpdateHandleData` | `(data: any, changedAttributeIds?: string[]) => void` | Called on every form field change with the current data and changed field IDs |
1156
+ | `bareUpdateHandlePreComplete` | `(data: any) => Promise<boolean>` | Called before save — return `false` to cancel |
1157
+ | `bareUpdateHandleComplete` | `(data: any) => Promise<any>` | Called after save completes |
1158
+ | `bareUpdateHandlePostComplete` | `(data: any) => Promise<any>` | Called after post-save operations complete |
1159
+ | `bareUpdateColumnType` | `"one" \| "two" \| "four"` | Form column layout: `"one"` = 2-col grid, `"two"` = 4-col grid (default), `"four"` = 4-col grid |
1160
+ | `bareUpdateTabComponent` | `(tabIds: string[]) => { tabId: string; icon?: ReactElement; skip?: boolean }[]` | Custom icons/skip flags for form tabs |
1161
+ | `bareUpdateActionBottom` | `boolean` | Plain right-aligned action row instead of the floating pill — for short forms inside a `Modal` |
1162
+ | `bareUpdateTabId` | `(tabId: string) => void` | Called when the active form tab changes |
1163
+ | `bareUpdateIndividualComponent` | `(columnId, ref, selectedData, setSelectedData) => ReactElement \| null` | Replaces a specific form field with a custom component |
1164
+ | `bareUpdateMobileView` | `boolean` | Renders the update form in mobile-optimised layout |
1165
+ | `bareOffline` | `boolean` | Enables offline data caching via IndexedDB |
1166
+ | `bareOfflineNetworkListener` | `boolean` | With `bareOffline`: follow `navigator.onLine` — saves go to the server while online and to IndexedDB only when the network is down. Without it every save goes to IndexedDB until `handleUploadOfflineData()` |
1167
+ | `bareOfflinePrefetchLimit` | `number` | With `bareOffline`: how many of the collection's latest docs to download into IndexedDB on mount (default 10) |
1168
+ | `bareOfflineReferences` | `Array<{ collectionId: string; limit?: number }>` | With `bareOffline`: reference collections to download on mount so reference dropdowns keep working offline |
1169
+ | `bareCSVImportEndpoint` | `string` | Custom CSV import endpoint |
1170
+ | `bareCSVExportEndpoint` | `string` | Custom CSV export endpoint |
1171
+ | `bareHideTableExtraMultipleAction` | `boolean` | Hides the extra multiple-action button in table view |
1074
1172
 
1075
1173
  ### Extended Tab
1076
1174
 
@@ -1138,6 +1236,16 @@ calendarSettings: {
1138
1236
  }
1139
1237
  ```
1140
1238
 
1239
+ ### Field visibility (`hideRead`)
1240
+
1241
+ `hideRead: true` on a DataStructure field:
1242
+
1243
+ - leaves the field out of the read view's field list;
1244
+ - on a `listObject`, `ganttchart` or `canvas` field, hides the whole field from the read view;
1245
+ - on a column inside a `listObject` (`objectData`), leaves that column out of the list-object table, in both the read and the update view. The row's edit popup still shows it, and the stored value is not changed.
1246
+
1247
+ *Pointers:* `src/components/data/dataTemplate/index.tsx`, `renderEachListObject` in `src/components/data/updateModule.tsx`
1248
+
1141
1249
  ### List / MultipleList Field Settings
1142
1250
 
1143
1251
  Properties specific to `type: "list"` and `type: "multipleList"` fields in the DataStructure schema.
@@ -1194,6 +1302,17 @@ Under `bareNewDTW` the feeds tab renders `NewFeeds` (timeline card that matches
1194
1302
  | `useColumnName` | `boolean` | Shows column name instead of column ID on cards |
1195
1303
  | `query` | `Query[]` | Additional queries to filter and organise kanban cards |
1196
1304
 
1305
+ ### Drive Settings
1306
+
1307
+ | Name | Type | Description |
1308
+ | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------ |
1309
+ | `nameColumnId` | `string` | A string column holding the file or folder name |
1310
+ | `kindColumnId` | `string` | A list column whose value is `folder` or `file` |
1311
+ | `parentColumnId` | `string` | The containing folder's row id. Missing, null or `""` means the top level |
1312
+ | `fileColumnId` | `string` | A `multipleFile` column holding the one uploaded file as `{ token, fileName }`, so the original name is kept |
1313
+ | `sizeColumnId` | `string` | Optional. A number column written with the file size in bytes on upload |
1314
+ | `mimeTypeColumnId` | `string` | Optional. A string column written with the file type on upload |
1315
+
1197
1316
  ### Map Settings
1198
1317
 
1199
1318
  | Name | Type | Description |
@@ -1208,10 +1327,10 @@ columns, persisted view state, SSE live) and **Consumer Fixtures** below.
1208
1327
  Every story mocks its own API and opens without a server.
1209
1328
 
1210
1329
  **Consumer fixtures** — `Data / Data Wrapper / Consumer Fixtures` holds the DataTemplateWrapper
1211
- configurations the apps run in production, copied field for field and self-mocked (no
1212
- server): the KPJ grant proposal form (Blixify Space's kpj-projects shape), Verdant's
1213
- installer pre- and post-installation checklists, its Sales Leads list and its simulator
1214
- proposal form, Meraque's offline work order, and an **Action Component Cases** story showing
1330
+ configurations taken from production apps and self-mocked (no server): a long
1331
+ grant-application form, installer pre- and post-installation checklists, a sales-leads list,
1332
+ a simulator proposal form, an offline work order, and an **Action Component Cases** story showing
1215
1333
  the update form under the three things `bareUpdateActionComponent` can return (undefined /
1216
1334
  own buttons / an empty fragment). Open them on a phone and a desktop before bumping the app — what changes
1217
- there is what changes in the app.
1335
+ there is what changes in the app. These fixtures mirror client projects, so they stay in
1336
+ the local Storybook and are excluded from the published MCP package.