blixify-ui-web-mcp 0.1.65 → 0.1.67

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.
@@ -478,7 +478,9 @@ A calendar tab has no view settings panel (it has no columns, sort or pages). Ro
478
478
 
479
479
  Under `bareNewDTW` the grid hides `Grid`'s own page buttons and renders the same `NewPagination` footer as the table and list views.
480
480
 
481
- Set `organise.viewId="grid"` (or add an `extendedTabs` entry with `viewType="grid"`) to render records as image cards. Use `bareSettings.bareListGridComponent` to fully customise each card, or use the built-in grid with `viewImage` pointing to an image column.
481
+ Set `organise.viewId="grid"` (or add an `extendedTabs` entry with `viewType="grid"`) to render records as cards. Use `bareSettings.bareListGridComponent` to fully customise each card, or use the built-in grid. `viewImage` is optional: point it at an image or multipleImage column to show a picture on each card, or leave it empty for cards with only the title and fields. The Add Tab modal offers **Grid** on every space, and shows the Preview Image picker only when the space has an image column.
482
+
483
+ The list, kanban and grid items show the view's visible columns in column order, with the table's cell renderers. The title column is the item's title, the grid's image column is its picture, and a column with nothing stored is left out. A button, timer or rating is always shown. Each item carries the edit pencil (only for users who can update) and the comment bubble (when `edit.activityLog` is on) beside its title.
482
484
 
483
485
  ```tsx
484
486
  <DataTemplate
@@ -759,8 +761,8 @@ Column types with monday.com counterparts. The value maths is in `src/components
759
761
  | Column | Schema | Stored value | Where it shows |
760
762
  | --- | --- | --- | --- |
761
763
  | Button | `type: "button"`, `buttonLabel?`, `buttonColour?`, `buttonConfirm?` | nothing | table, list, kanban and read view; never in a form. A tap calls `organise.onButtonClick(columnId, row)` and the button stays busy until the returned promise settles, ignoring taps meanwhile. `buttonConfirm` asks first. Disabled without `onButtonClick` or update rights |
762
- | Time tracking | `type: "timeTracking"` | `{ totalSeconds, running, startedAt?, sessions? }` | table and read view show the total with start / stop, ticking each second inside the cell only; a form shows the total read-only. Start / stop saves that one field. `handleStartTimeTracking` / `handleStopTimeTracking` are idempotent, so a flow can drive the same value. Sorts on `<id>.totalSeconds`; formulas read hours (`handleGetTimeTrackingHours`) |
763
- | Date range | `type: "dateRange"`, `minDate?`, `maxDate?` | `{ start, end }` | `12 – 18 Nov`; a range picker in the form; filters and sorts on `<id>.start`. A calendar or timeline tab can use `<id>.start` and `<id>.end` as its dates |
764
+ | Time tracking | `type: "timeTracking"` | `{ totalSeconds, running, startedAt?, sessions? }` | table, read view and the record form show the total with start / stop, ticking each second inside the cell only; the form draws it as a field box, read-only on a record not created yet or without update rights. Start / stop saves at once, apart from Submit, and a form save never sends the timer. With `organise.onTimeTrackingAction` a click sends only `"start"` / `"stop"` and shows the value the host's server stored, timed on the server's clock (the cell ticks at once and is corrected to the reply, or put back if it fails); without it the cell works the value out and saves that one field. `handleStartTimeTracking` / `handleStopTimeTracking` are idempotent, so a flow can drive the same value. Sorts on `<id>.totalSeconds`; formulas read hours (`handleGetTimeTrackingHours`) |
765
+ | Date range | `type: "dateRange"`, `minDate?`, `maxDate?` | `{ start, end }` | `12 – 18 Nov`; a range picker in the form; in an editable table the whole cell opens it, with the inline date cell's border on hover; filters and sorts on `<id>.start`. A calendar or timeline tab can use `<id>.start` and `<id>.end` as its dates |
764
766
  | Rating | `type: "number"`, `ratingMax` | a number | stars in every view; a tap saves the number, tapping the current rating clears it |
765
767
 
766
768
  `bareSettings.bareSystemColumns` adds the server-stamped columns without declaring them: Created At / By (`baseCreatedAt`, `baseCreatedBy`), Updated At / By (`baseUpdatedAt`, `baseUpdatedBy`), Record ID (the record's `_id`) and Number (`baseNumber`). They start hidden; showing one is kept per view (`shownSystemColumnIds`) and never written back through `onChangeHide` or `onChangeDrag`. They are read-only, sortable and filterable, empty on a record the server never stamped, and a form save never sends them (nor a timer or a button).
@@ -1065,7 +1067,7 @@ const devSettings = parseWorkspaceSettings(
1065
1067
  | `uploadEndpoint` | `string` | Upload endpoint (required when `imageEndpoint` is custom) |
1066
1068
  | `bucketName` | `string` | Storage bucket name (required for AWS/GCS) |
1067
1069
  | `maxFileSize` | `number` | Global max file size in MB for uploads |
1068
- | `organisationMembers` | `Option[]` | Member list used for `person` / `listPerson` field types |
1070
+ | `organisationMembers` | `Option[]` | Member list used for `person` / `listPerson` field types. An option's `image` is the member's photo, shown in cells, the person picker and its tags; a member without one shows their initials |
1069
1071
  | `roleOptions` | `Option[]` | Role list used for `roles` field type |
1070
1072
  | `currentUser` | `{ userEmail: string; userName: string }` | Current user info used for export email and QR features |
1071
1073
  | `importEndpoint` | `string` | Firebase CSV import function URL |
@@ -1099,7 +1101,7 @@ modal is also opened through the imperative `handleDeleteModal`.
1099
1101
  | Inline cell edit and its write | `listEditable && !disabledUpdate` |
1100
1102
  | Kanban boolean checkbox and its write | `listEditable && !disabledUpdate` |
1101
1103
  | Read-view Update button | `allEditable && !disabledUpdate` |
1102
- | List Update column | `allEditable && !disabledUpdate`, or `bareListMultipleSelectAddtionalActions` |
1104
+ | List Update column | `allEditable && !disabledUpdate`, or `bareListMultipleSelectAddtionalActions`. Under `bareNewDTW` there is no Update column: a record opens from its title (Update is in the record), cells edit in place and the comment bubble sits beside the title. An Actions column shows only when `bareListActionBtns` is given, with just those buttons |
1103
1105
  | Batch update, clone, change-to-draft | `allEditable && !disabledUpdate && !disableBatchUpdate` (the batch Update button also requires a non-Firebase backend) |
1104
1106
  | Delete button, batch delete, map delete | `deleteBtn` (independent of `allEditable`) |
1105
1107
  | Map polygon select | batch-update or delete permission |
@@ -1208,7 +1210,7 @@ Which field types can be edited from the list table, and how. Types not listed u
1208
1210
  | `addColumnEnabled` | `boolean` | Shows an add-column button in the table header |
1209
1211
  | `persistViewState` | `"persistent" \| "session"` | Remembers the list's sort, filters, hidden columns, page, rows per page, search and reading position 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`. The reading position is restored on mount and on returning from a record, not on a tab switch; with several lists on one page, only the list a record was last opened from restores (tracked in `blixify-dtw-persist-last-drill`). Covers table, list, grid, kanban and feeds; not map. List view only |
1210
1212
  | `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` |
1211
- | `savedViews` | `boolean` | Shows a row of view tags under the tab bar: save the current filters, flex filters, sort, rows per page, grouping and columns under a name, reapply it, update it or delete it. Views belong to the tab they were saved on and are kept in `localStorage` under `blixify-dtw-views-<collectionId>[-<persistKey>][-<currentUser.userEmail>]`. Sort is held by the template while it is on, as with `persistViewState`, and applying a view calls `onChangeSort`, `onChangeGroupBy`, `onChangePagination(0)` and `bareListHandleFilter` when those change. Each write re-reads storage first, so views saved in another browser tab are kept. With `onChangeHide` / `onChangeDrag`, a view's hides and column order stay on screen only: a toggle or reorder after applying one writes back the schema's columns plus that single change |
1213
+ | `savedViews` | `boolean` | Shows a row of view tags under the tab bar: save the current filters, flex filters, sort, rows per page, grouping, columns and column widths under a name, reapply it, update it or delete it. Views belong to the tab they were saved on and are kept in `localStorage` under `blixify-dtw-views-<collectionId>[-<persistKey>][-<currentUser.userEmail>]`. Sort is held by the template while it is on, as with `persistViewState`, and applying a view calls `onChangeSort`, `onChangeGroupBy`, `onChangePagination(0)` and `bareListHandleFilter` when those change. Each write re-reads storage first, so views saved in another browser tab are kept. With `onChangeHide` / `onChangeDrag`, a view's hides and column order stay on screen only: a toggle or reorder after applying one writes back the schema's columns plus that single change |
1212
1214
  | `defaultSavedViews` | `DefaultSavedView[]` | Views provided by the app (`{ id?, name, tabId?, state }`), listed before the user's own and never deleted. Without `tabId` a view is listed on every tab. A field left out of `state` is reset to its default when the view is applied. `id` must be unique; without one the view gets `default-<index>`, its position in the whole array |
1213
1215
  | `sharedViews` | `SharedSavedView[]` | Views the app stores for everyone (`{ id, name, tabId, state }`), e.g. on the record the list belongs to. Given, it replaces this browser's storage: the list shows only these, saving goes to `onChangeSharedViews`, and nothing is read from or written to `localStorage` |
1214
1216
  | `onChangeSharedViews` | `(views: SharedSavedView[]) => void` | Called with the whole list after a view is saved, updated or deleted, for the app to store and pass back as `sharedViews`; a second change before it comes back builds on the list just sent. The whole list is replaced each time, so two editors saving at once is last-writer-wins. Without it the app's views are read-only and “+ Save view” is hidden |
@@ -1217,6 +1219,9 @@ Which field types can be edited from the list table, and how. Types not listed u
1217
1219
  | `initialSavedViewId` | `string` | A view the list opens on, once, in place of the ★ default — e.g. a page embedding a datasheet opens it on a chosen view. A view that no longer exists, or is on another tab, leaves the list on All. Opening on it does not call `onChangeSort` |
1218
1220
  | `groupBy` | `string` | Column ID to group list results by. With `bareNewDTW` the groups are bands in one table. Grouped by a `list` or `boolean` column, every option (in option order, with its colour) plus "Unknown" (a value outside the options) and "No Value" (missing or blank) is a band with its real total that reads its own rows under the list's filters, search and sort: in scroll mode each band loads more as it scrolls, in page mode each band has its own pager and the list-wide pager is hidden. Grouped by any other column (a `person` column's sections follow the member order), page mode groups the rows of the current page and scroll mode keeps the normal scroll; a section built from loaded rows draws 50 rows and a "Show more" at a time. A search, filter, sort or regroup starts every band over. Firebase and `bareListMobileView` keep the normal pagination. Saved views store and restore it |
1219
1221
  | `onButtonClick` | `(columnId: string, row: any) => Promise<any> \| void` | Called when a `button` column is tapped, with the stored record. The button is busy until the promise settles. See Button, time tracking … columns |
1222
+ | `onTimeTrackingAction` | `(columnId: string, row: any, action: "start" \| "stop") => Promise<any>` | Starts or stops a `timeTracking` timer on the host's server, with the stored record. Resolve with the value the server stored; the timer shows it, and goes back to where it was if the promise rejects. Without it a timer works its value out on the device and saves it through the single-field update |
1223
+ | `allView` | `PersistedViewState` | All's settings as the app stores them for everyone (`{}` when none are saved yet): sort, grouping, filters, hidden columns, column order, column widths (`columnWidths`, `"180px"` by column id) and rows per page. A setting left out falls back to the model and the props. Needs `savedViews`. Given, the list opens on it, and every change a person makes to All or a saved view is kept in their browser (`blixify-dtw-draft-<collectionId>[-<persistKey>][-<currentUser.userEmail>]-<all \| view id>`) until they choose Update or Reset; a saved view with no width of its own for a column follows All's |
1224
+ | `onChangeAllView` | `(state: PersistedViewState) => void` | Saves All's settings for everyone. Given, “Update All” shows beside “+ Save view” while All on screen differs from `allView`. Without it a person's changes stay in their own browser; “Reset” goes back to the stored view either way |
1220
1225
  | `onChangeGroupBy` | `(groupBy: string) => void` | Called when the user picks another grouping in the group-by selector or by applying a saved view (`""` for none), so the app can store it with the tab. Not called when the list opens on a view |
1221
1226
  | `groupIdCollapsible` | `{ [key: string]: boolean }` | Initial collapsed/expanded state per group ID |
1222
1227
  | `sortGroupByAlphabetically` | `boolean` | Sorts group-by values alphabetically |
@@ -1302,7 +1307,7 @@ Injects custom React components and callbacks into the list, read, and update vi
1302
1307
  | `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 |
1303
1308
  | `bareReadListTabs` | `boolean` | Shows list-style tabs in read view |
1304
1309
  | `bareListComponent` | `(data, prettierData, loading, pageIndex) => any` | Fully replaces the list UI. `data` is the fetched records (`_id` exposed as `id`), `prettierData` the display rows |
1305
- | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons on each list row. `data` is the raw fetched record |
1310
+ | `bareListActionBtns` | `(data: any) => ReactElement[]` | Extra icon buttons on each list row. `data` is the raw fetched record. Under `bareNewDTW` they are the only content of the table's Actions column |
1306
1311
  | `bareListMultipleSelectAddtionalActions` | `{ text: string; className?: string; onClick: (ids, selectAll, query) => void }[]` | Extra bulk-action buttons shown when rows are selected |
1307
1312
  | `bareListGridComponent` | `(data: any, rawData?: any) => any` | Custom card renderer for grid/kanban view. `data` is display data; `rawData` is the fetched record for that card (`_id` exposed as `id`) |
1308
1313
  | `bareListGridColClassName` | `string` | Tailwind class for grid column width |
@@ -17,6 +17,10 @@ Sectioned card board. Desktop: horizontal columns. Mobile: tab switcher between
17
17
 
18
18
  `mobileView` swaps the column row for a tab rail with one column visible. The first column is selected as soon as columns exist (data usually arrives after the first render). `className` styles the desktop column row only — the stacked phone layout ignores it, so a `flex` / `inline-flex` passed for the desktop row cannot turn the phone view into a row. Rail, count badges, hint text and the default card follow `darkMode`.
19
19
 
20
+ ## Edit pencil and comment bubble
21
+
22
+ `onCardEdit(id)` and `onCardActivity(id)` add an edit pencil and a comment bubble to the default card's header. Neither opens the card or starts a drag. Under `bareNewDTW`, DataTemplate passes the pencil only to users who can update records.
23
+
20
24
  ## Lane colours
21
25
 
22
26
  Each lane carries an accent colour: a coloured top border and a matching dot beside its title (and on its tab in the phone view). Colours come from a fixed palette in lane order. `Unassigned` is always grey and is left out of the order, so switching `nullColumn` on does not change any other lane's colour. When `columns` is passed, a column's own `color` (any CSS colour) is used as it is.
@@ -66,6 +66,10 @@ The legacy `List` renders **every** extra key on an item. `NewList` renders only
66
66
 
67
67
  ChatDashboard's conversation list uses all four.
68
68
 
69
+ ## Edit pencil and comment bubble
70
+
71
+ `onRowEdit(id)` and `onRowActivity(id)` add an edit pencil and a comment bubble beside each item's title. Neither opens the row or follows its link, and neither makes the row taller. Under `bareNewDTW`, DataTemplate passes the pencil only to users who can update records.
72
+
69
73
  ## Status
70
74
 
71
75
  🚧 **Scaffold only.** Implementation lands in follow-up commits per #1714.
@@ -6,6 +6,8 @@ Tabular display with a List-shaped mobile breakpoint. The architectural key: **`
6
6
 
7
7
  Pass `onRowActivity={(id) => ...}` to show a keyboard-accessible chat button at the right of the first visible cell (beside the title on mobile cards). It stops row navigation and does not enter inline editing. When no left pins are configured, the first ungrouped column is pinned automatically; existing pin configurations are preserved. DTW wires this callback automatically when `edit.activityLog` is enabled with `bareNewDTW`.
8
8
 
9
+ Pass `onRowEdit={(id) => ...}` as well to put an edit pencil before the chat button, at the same size and colour. Both sit over the cell's right padding, so the row does not grow. DTW passes it only when the user can update records (`edit.allEditable`) and opens the record's edit form with `handleNavigate("update", id, "general")`.
10
+
9
11
  ## Adding a row
10
12
 
11
13
  With `addable.active`, a `+` row at the bottom starts a new record where the click lands. While it is filled in, ✓ and ✕ sit in the Actions column and **Save** and **Cancel** are repeated under the row, held at the left edge as the table scrolls sideways. Enter saves and opens the next row, Escape cancels, and clicking another row saves it.
@@ -56,17 +58,23 @@ With `mobileView`, `mobileTooltip` adds row data to the collapsed row and to a h
56
58
  Drag the grip on a header's right border to resize that column. The line is
57
59
  invisible at rest, fades in when the header is hovered so the affordance is
58
60
  discoverable, and turns primary when the grip itself is hovered. The hit area is
59
- 8px and straddles the border, so it does not need pixel hunting. The width is held
60
- in component state, keyed by column key — a resize is a per-viewer preference, and
61
- there is no storage for it yet, so it resets when the list unmounts.
62
-
63
- `col.width` stays the way a consumer sets a static width (a Tailwind class such as
64
- `w-48`). A dragged width overrides it through an inline style, because Tailwind
65
- generates classes at build time and cannot emit a runtime `w-[Npx]`. Resolution
66
- order is dragged width → `col.width` class → measured / auto, and pinned columns
67
- measure from the dragged width once one is set. The default minimum is 80px, but a column configured narrower than that (a 40px
68
- icon column, say) keeps its own width as the floor — a resize never forces a
69
- column wider than the consumer asked for.
61
+ 8px and straddles the border, so it does not need pixel hunting.
62
+
63
+ `advSettings.onResizeColumn(columnId, width)` is called once, when the drag is
64
+ released and only if the width changed, with the width in pixels. Given, the
65
+ caller keeps the width and passes it back as the column's `width` (DataTemplate
66
+ does, as `"180px"`). Without it the dragged width is held in component state and
67
+ resets when the list unmounts.
68
+
69
+ `col.width` is read in any of the forms a schema stores: `"180px"`, `"180"`, a
70
+ Tailwind arbitrary width (`w-[180px]`) or a spacing class (`w-48`). Any of them
71
+ is drawn as an inline style, because Tailwind generates classes at build time
72
+ and cannot emit a runtime `w-[Npx]`; anything else (`"200%"`, `w-full`) stays a
73
+ class. Resolution order is dragged width → `col.width` → measured / auto, and
74
+ pinned columns measure from the same width. The default minimum is 80px, but a
75
+ column configured narrower than that (a 40px icon column, say) keeps its own
76
+ width as the floor — a resize never forces a column wider than the consumer
77
+ asked for.
70
78
 
71
79
  The grip is part of `NewTable` itself, so it appears wherever the component is
72
80
  used, not only inside a DataTemplate.
@@ -95,6 +95,7 @@ Async / database search:
95
95
  | `size` | `"xs"` | — | Compact field that looks 12px everywhere: on phones it keeps 16px text and draws the trigger at 75%, so iOS Safari does not zoom on focus; from `sm` up it is a plain 12px field |
96
96
  | `dropdownClassName` | `string` | — | Tailwind classes for the dropdown list |
97
97
  | `imageClassName` | `string` | — | Tailwind classes for option images (used with `type="button"`) |
98
+ | `showOptionAvatar` | `boolean` | `false` | Options are people: each option, the picked value and each tag shows the option's `image` as a 24px round photo, or its initials on a colour from its label when it has none or the photo fails to load |
98
99
  | `onChange` | `(value: string \| string[]) => void` | — | Called with the updated value when selection changes |
99
100
  | `onSearch` | `(value: string) => void` | — | Called as the user types. Use to fetch options dynamically |
100
101
  | `cellInput` | `CellInput` | — | Cell input config for use inside a Table component |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blixify-ui-web-mcp",
3
- "version": "0.1.65",
3
+ "version": "0.1.67",
4
4
  "license": "MIT",
5
5
  "main": "lib/mcp/server.js",
6
6
  "bin": {