@pilotiq/pilotiq 0.24.1 → 0.24.3
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.
- package/CHANGELOG.md +57 -0
- package/boost/guidelines.md +571 -0
- package/boost/skills/pilotiq-actions/SKILL.md +49 -0
- package/boost/skills/pilotiq-actions/rules/dispatch-modes.md +177 -0
- package/boost/skills/pilotiq-actions/rules/factories.md +130 -0
- package/boost/skills/pilotiq-actions/rules/visibility-and-authorization.md +125 -0
- package/boost/skills/pilotiq-fields/SKILL.md +47 -0
- package/boost/skills/pilotiq-fields/rules/field-catalog.md +288 -0
- package/boost/skills/pilotiq-fields/rules/reactive-fields.md +199 -0
- package/boost/skills/pilotiq-fields/rules/validation.md +198 -0
- package/boost/skills/pilotiq-relations/SKILL.md +47 -0
- package/boost/skills/pilotiq-relations/rules/relation-managers.md +256 -0
- package/boost/skills/pilotiq-relations/rules/repeater-relationship.md +177 -0
- package/boost/skills/pilotiq-resource/SKILL.md +61 -0
- package/boost/skills/pilotiq-resource/rules/authorization.md +242 -0
- package/boost/skills/pilotiq-resource/rules/defining-resources.md +228 -0
- package/boost/skills/pilotiq-resource/rules/page-overrides.md +296 -0
- package/dist/Pilotiq.d.ts +31 -0
- package/dist/Pilotiq.d.ts.map +1 -1
- package/dist/Pilotiq.js +3 -1
- package/dist/Pilotiq.js.map +1 -1
- package/dist/PilotiqRegistry.d.ts +13 -0
- package/dist/PilotiqRegistry.d.ts.map +1 -1
- package/dist/PilotiqRegistry.js +15 -0
- package/dist/PilotiqRegistry.js.map +1 -1
- package/dist/pageData/misc.d.ts.map +1 -1
- package/dist/pageData/misc.js +6 -0
- package/dist/pageData/misc.js.map +1 -1
- package/dist/pageData/navigation.d.ts +1 -0
- package/dist/pageData/navigation.d.ts.map +1 -1
- package/dist/pageData/navigation.js +3 -0
- package/dist/pageData/navigation.js.map +1 -1
- package/dist/pageData/relationPages.d.ts.map +1 -1
- package/dist/pageData/relationPages.js +3 -0
- package/dist/pageData/relationPages.js.map +1 -1
- package/dist/pageData/resourcePages.d.ts.map +1 -1
- package/dist/pageData/resourcePages.js +8 -0
- package/dist/pageData/resourcePages.js.map +1 -1
- package/dist/react/AppShell.d.ts +8 -0
- package/dist/react/AppShell.d.ts.map +1 -1
- package/dist/react/AppShell.js.map +1 -1
- package/dist/react/layouts/SidebarLayout.d.ts.map +1 -1
- package/dist/react/layouts/SidebarLayout.js +10 -2
- package/dist/react/layouts/SidebarLayout.js.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.d.ts.map +1 -1
- package/dist/react/widgets/StatsOverviewRenderer.js +32 -18
- package/dist/react/widgets/StatsOverviewRenderer.js.map +1 -1
- package/dist/routes/relations.d.ts.map +1 -1
- package/dist/routes/relations.js +25 -18
- package/dist/routes/relations.js.map +1 -1
- package/dist/routes/resources.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build.log +0 -8
- package/CLAUDE.md +0 -265
- package/src/Cluster.test.ts +0 -283
- package/src/Cluster.ts +0 -83
- package/src/Column.test.ts +0 -199
- package/src/Column.ts +0 -710
- package/src/Global.test.ts +0 -367
- package/src/Global.ts +0 -169
- package/src/Page.test.ts +0 -114
- package/src/Page.ts +0 -208
- package/src/Pilotiq.perf.test.ts +0 -252
- package/src/Pilotiq.test.ts +0 -129
- package/src/Pilotiq.ts +0 -1158
- package/src/PilotiqRegistry.ts +0 -36
- package/src/PilotiqServiceProvider.ts +0 -121
- package/src/RelationManager.test.ts +0 -400
- package/src/RelationManager.ts +0 -527
- package/src/RenderHook.test.ts +0 -252
- package/src/RenderHook.ts +0 -242
- package/src/Resource.test.ts +0 -284
- package/src/Resource.ts +0 -526
- package/src/RightPanel.test.ts +0 -202
- package/src/RightPanel.ts +0 -132
- package/src/Tab.test.ts +0 -91
- package/src/Tab.ts +0 -156
- package/src/UserMenuItem.ts +0 -145
- package/src/actions/Action.test.ts +0 -2526
- package/src/actions/Action.ts +0 -1515
- package/src/actions/ActionGroup.test.ts +0 -112
- package/src/actions/ActionGroup.ts +0 -173
- package/src/actions/attachFactory.ts +0 -172
- package/src/actions/bulkFactories.ts +0 -168
- package/src/actions/crudFactories.ts +0 -220
- package/src/actions/exportFactory.ts +0 -225
- package/src/actions/factoryHelpers.ts +0 -177
- package/src/actions/importFactory.ts +0 -243
- package/src/actions/index.ts +0 -17
- package/src/actions/m2mFactories.ts +0 -193
- package/src/actions/relationFactories.ts +0 -372
- package/src/applyPageHooks.test.ts +0 -463
- package/src/applyPageHooks.ts +0 -330
- package/src/authorization.test.ts +0 -483
- package/src/breadcrumbs.test.ts +0 -238
- package/src/cells/coerce.test.ts +0 -85
- package/src/cells/coerce.ts +0 -84
- package/src/clusterPaths.ts +0 -35
- package/src/columns/BadgeColumn.test.ts +0 -54
- package/src/columns/BadgeColumn.ts +0 -32
- package/src/columns/BooleanColumn.test.ts +0 -41
- package/src/columns/BooleanColumn.ts +0 -18
- package/src/columns/ColorColumn.test.ts +0 -37
- package/src/columns/ColorColumn.ts +0 -38
- package/src/columns/IconColumn.test.ts +0 -54
- package/src/columns/IconColumn.ts +0 -37
- package/src/columns/ImageColumn.test.ts +0 -41
- package/src/columns/ImageColumn.ts +0 -28
- package/src/columns/SelectColumn.ts +0 -98
- package/src/columns/TextColumn.test.ts +0 -190
- package/src/columns/TextColumn.ts +0 -20
- package/src/columns/TextInputColumn.ts +0 -68
- package/src/columns/ToggleColumn.ts +0 -46
- package/src/columns/editableColumns.test.ts +0 -238
- package/src/columns/index.ts +0 -9
- package/src/defaultGlobalPages.ts +0 -95
- package/src/defaultPages.test.ts +0 -634
- package/src/defaultPages.ts +0 -617
- package/src/defaultViewPage.test.ts +0 -147
- package/src/elements/Form.test.ts +0 -223
- package/src/elements/Form.ts +0 -416
- package/src/elements/ListTabs.ts +0 -28
- package/src/elements/Table.test.ts +0 -422
- package/src/elements/Table.ts +0 -850
- package/src/elements/TableGroup.test.ts +0 -260
- package/src/elements/TableGroup.ts +0 -334
- package/src/elements/dispatchAction.test.ts +0 -463
- package/src/elements/dispatchAction.ts +0 -355
- package/src/elements/dispatchForm.test.ts +0 -477
- package/src/elements/dispatchForm.ts +0 -1993
- package/src/elements/dispatchTable.test.ts +0 -1514
- package/src/elements/dispatchTable.ts +0 -745
- package/src/elements/index.ts +0 -21
- package/src/entries/BadgeEntry.ts +0 -39
- package/src/entries/CodeEntry.test.ts +0 -40
- package/src/entries/CodeEntry.ts +0 -52
- package/src/entries/ColorEntry.ts +0 -63
- package/src/entries/ComponentEntry.test.ts +0 -173
- package/src/entries/ComponentEntry.ts +0 -95
- package/src/entries/Entry.ts +0 -304
- package/src/entries/IconEntry.ts +0 -49
- package/src/entries/ImageEntry.ts +0 -61
- package/src/entries/KeyValueEntry.ts +0 -47
- package/src/entries/RepeatableEntry.test.ts +0 -239
- package/src/entries/RepeatableEntry.ts +0 -173
- package/src/entries/TextEntry.test.ts +0 -394
- package/src/entries/TextEntry.ts +0 -60
- package/src/entries/index.ts +0 -12
- package/src/entries/leaves.test.ts +0 -306
- package/src/entries/registry.ts +0 -54
- package/src/fields/BuilderField.test.ts +0 -1188
- package/src/fields/BuilderField.ts +0 -605
- package/src/fields/BuilderRelationship.test.ts +0 -811
- package/src/fields/CheckboxField.test.ts +0 -44
- package/src/fields/CheckboxField.ts +0 -27
- package/src/fields/CheckboxListField.test.ts +0 -99
- package/src/fields/CheckboxListField.ts +0 -66
- package/src/fields/ColorPickerField.test.ts +0 -33
- package/src/fields/ColorPickerField.ts +0 -25
- package/src/fields/DateField.ts +0 -54
- package/src/fields/DateTimeField.test.ts +0 -55
- package/src/fields/EmailField.ts +0 -16
- package/src/fields/Field.test.ts +0 -654
- package/src/fields/Field.ts +0 -817
- package/src/fields/FileUploadField.test.ts +0 -143
- package/src/fields/FileUploadField.ts +0 -159
- package/src/fields/HiddenField.test.ts +0 -27
- package/src/fields/HiddenField.ts +0 -28
- package/src/fields/KeyValueField.test.ts +0 -105
- package/src/fields/KeyValueField.ts +0 -55
- package/src/fields/MarkdownField.test.ts +0 -167
- package/src/fields/MarkdownField.ts +0 -162
- package/src/fields/NumberField.ts +0 -33
- package/src/fields/RadioField.test.ts +0 -94
- package/src/fields/RadioField.ts +0 -67
- package/src/fields/RepeaterField.test.ts +0 -1806
- package/src/fields/RepeaterField.ts +0 -939
- package/src/fields/RepeaterRelationship.test.ts +0 -1923
- package/src/fields/RepeaterSimple.test.ts +0 -248
- package/src/fields/RowButton.test.ts +0 -219
- package/src/fields/RowButton.ts +0 -135
- package/src/fields/SelectField.test.ts +0 -192
- package/src/fields/SelectField.ts +0 -235
- package/src/fields/SliderField.test.ts +0 -50
- package/src/fields/SliderField.ts +0 -53
- package/src/fields/SlugField.ts +0 -24
- package/src/fields/TagsInputField.test.ts +0 -154
- package/src/fields/TagsInputField.ts +0 -133
- package/src/fields/TextField.test.ts +0 -213
- package/src/fields/TextField.ts +0 -177
- package/src/fields/TextareaField.test.ts +0 -58
- package/src/fields/TextareaField.ts +0 -59
- package/src/fields/ToggleButtonsField.test.ts +0 -106
- package/src/fields/ToggleButtonsField.ts +0 -59
- package/src/fields/ToggleField.ts +0 -16
- package/src/fields/disableOptionsWhenSelectedInSiblingRepeaterItems.test.ts +0 -319
- package/src/fields/optionsResolver.ts +0 -95
- package/src/fields/resolveField.ts +0 -28
- package/src/filters/BooleanFilter.ts +0 -35
- package/src/filters/DateRangeFilter.test.ts +0 -194
- package/src/filters/DateRangeFilter.ts +0 -148
- package/src/filters/Filter.test.ts +0 -268
- package/src/filters/Filter.ts +0 -184
- package/src/filters/FormFilter.test.ts +0 -238
- package/src/filters/FormFilter.ts +0 -215
- package/src/filters/MultiSelectFilter.test.ts +0 -119
- package/src/filters/MultiSelectFilter.ts +0 -78
- package/src/filters/QueryBuilderFilter.test.ts +0 -662
- package/src/filters/QueryBuilderFilter.ts +0 -398
- package/src/filters/SelectFilter.ts +0 -46
- package/src/filters/TernaryFilter.test.ts +0 -160
- package/src/filters/TernaryFilter.ts +0 -72
- package/src/filters/TrashedFilter.test.ts +0 -149
- package/src/filters/TrashedFilter.ts +0 -55
- package/src/filters/queryBuilder/BooleanConstraint.ts +0 -31
- package/src/filters/queryBuilder/Constraint.ts +0 -115
- package/src/filters/queryBuilder/DateConstraint.ts +0 -69
- package/src/filters/queryBuilder/NumberConstraint.ts +0 -66
- package/src/filters/queryBuilder/SelectConstraint.ts +0 -72
- package/src/filters/queryBuilder/TextConstraint.ts +0 -64
- package/src/filters/queryBuilder/index.ts +0 -12
- package/src/icons/index.ts +0 -2
- package/src/icons/lucide.ts +0 -204
- package/src/icons/registry.test.ts +0 -56
- package/src/icons/registry.ts +0 -41
- package/src/icons/types.ts +0 -47
- package/src/index.ts +0 -525
- package/src/io/csv.test.ts +0 -142
- package/src/io/csv.ts +0 -170
- package/src/nestedRelationManagerData.test.ts +0 -547
- package/src/notifications/Notification.test.ts +0 -210
- package/src/notifications/Notification.ts +0 -354
- package/src/notifications/broadcast.test.ts +0 -110
- package/src/notifications/broadcast.ts +0 -95
- package/src/notifications/database.test.ts +0 -383
- package/src/notifications/database.ts +0 -398
- package/src/notifications/databaseNotifications.test.ts +0 -187
- package/src/notifications/dispatchNotificationAction.test.ts +0 -341
- package/src/notifications/dispatchNotificationAction.ts +0 -142
- package/src/notifications/flash.test.ts +0 -89
- package/src/notifications/flash.ts +0 -71
- package/src/notifications/index.ts +0 -45
- package/src/notifications/registerBroadcastAuth.test.ts +0 -134
- package/src/notifications/registerBroadcastAuth.ts +0 -100
- package/src/notifications/resolveSavedNotification.test.ts +0 -82
- package/src/notifications/resolveSavedNotification.ts +0 -59
- package/src/notifications/types.ts +0 -93
- package/src/orm/m2mAccessor.ts +0 -66
- package/src/orm/modelDefaults.test.ts +0 -633
- package/src/orm/modelDefaults.ts +0 -666
- package/src/pageData/breadcrumbs.ts +0 -288
- package/src/pageData/forms.ts +0 -578
- package/src/pageData/helpers.ts +0 -857
- package/src/pageData/misc.ts +0 -347
- package/src/pageData/navigation.ts +0 -842
- package/src/pageData/relationPages.ts +0 -1248
- package/src/pageData/relationTabs.ts +0 -286
- package/src/pageData/resourcePages.ts +0 -609
- package/src/pageData.test.ts +0 -1545
- package/src/pageData.ts +0 -341
- package/src/plugins/index.ts +0 -8
- package/src/plugins/themeEditor.test.ts +0 -36
- package/src/plugins/themeEditor.ts +0 -45
- package/src/react/AppShell.tsx +0 -251
- package/src/react/CollabExtensionFactoryRegistry.ts +0 -55
- package/src/react/CollabRoomContext.ts +0 -98
- package/src/react/CollabTextRendererRegistry.ts +0 -102
- package/src/react/CommandPalette.tsx +0 -375
- package/src/react/CurrentUserContext.tsx +0 -50
- package/src/react/CustomPageWrapperGate.tsx +0 -69
- package/src/react/CustomPageWrapperRegistry.ts +0 -45
- package/src/react/FieldFocusReporterRegistry.ts +0 -37
- package/src/react/FieldLabelSlotRegistry.ts +0 -30
- package/src/react/FieldPresenceRegistry.ts +0 -46
- package/src/react/FormCollabBindingRegistry.ts +0 -242
- package/src/react/FormStateContext.tsx +0 -591
- package/src/react/HeadHooks.tsx +0 -126
- package/src/react/MarkdownEditorRegistry.test.ts +0 -38
- package/src/react/MarkdownEditorRegistry.ts +0 -107
- package/src/react/NotificationActionStrip.tsx +0 -263
- package/src/react/NotificationBell.tsx +0 -426
- package/src/react/PendingSuggestionApplierRegistry.test.ts +0 -97
- package/src/react/PendingSuggestionApplierRegistry.ts +0 -98
- package/src/react/PendingSuggestionOverlayRegistry.ts +0 -54
- package/src/react/PendingSuggestionsContext.tsx +0 -172
- package/src/react/RecordWrapperGate.tsx +0 -58
- package/src/react/RecordWrapperRegistry.ts +0 -39
- package/src/react/RenderHookSlot.tsx +0 -32
- package/src/react/RightSidebar.tsx +0 -257
- package/src/react/RightSidebarContext.tsx +0 -234
- package/src/react/RightSidebarTrigger.tsx +0 -53
- package/src/react/RowCoordsContext.tsx +0 -23
- package/src/react/SchemaRenderer.tsx +0 -549
- package/src/react/SearchTrigger.tsx +0 -46
- package/src/react/ThemeProvider.tsx +0 -93
- package/src/react/ThemeSettingsPage.tsx +0 -579
- package/src/react/ThemeToggle.tsx +0 -20
- package/src/react/Toaster.tsx +0 -158
- package/src/react/UserMenu.tsx +0 -196
- package/src/react/WidgetDataContext.tsx +0 -157
- package/src/react/cells/EditableCell.tsx +0 -389
- package/src/react/component-slots.test.ts +0 -103
- package/src/react/component-slots.ts +0 -116
- package/src/react/fieldJsHandler.test.ts +0 -166
- package/src/react/fieldJsHandler.ts +0 -79
- package/src/react/fields/BuilderInput.tsx +0 -1078
- package/src/react/fields/CheckboxInput.tsx +0 -39
- package/src/react/fields/CheckboxListInput.tsx +0 -102
- package/src/react/fields/ColorInput.tsx +0 -71
- package/src/react/fields/DateFieldInput.tsx +0 -70
- package/src/react/fields/DateTimeInput.tsx +0 -62
- package/src/react/fields/FieldShell.tsx +0 -348
- package/src/react/fields/FileUploadInput.tsx +0 -639
- package/src/react/fields/HiddenInput.tsx +0 -17
- package/src/react/fields/KeyValueInput.tsx +0 -230
- package/src/react/fields/MarkdownInput.tsx +0 -560
- package/src/react/fields/RadioInput.tsx +0 -81
- package/src/react/fields/RepeaterInput.test.ts +0 -116
- package/src/react/fields/RepeaterInput.tsx +0 -1420
- package/src/react/fields/SelectFieldInput.tsx +0 -280
- package/src/react/fields/SliderInput.tsx +0 -81
- package/src/react/fields/TagsInput.tsx +0 -283
- package/src/react/fields/TextLikeInput.tsx +0 -256
- package/src/react/fields/ToggleButtonsInput.tsx +0 -60
- package/src/react/fields/ToggleFieldInput.tsx +0 -56
- package/src/react/fields/relationshipRenameDispatch.test.ts +0 -106
- package/src/react/fields/relationshipRenameDispatch.ts +0 -97
- package/src/react/fields/repeaterReconcile.test.ts +0 -114
- package/src/react/fields/repeaterReconcile.ts +0 -104
- package/src/react/fields/rowChromeButton.tsx +0 -336
- package/src/react/fields/rowState.ts +0 -106
- package/src/react/fields/syncRowGates.test.ts +0 -202
- package/src/react/fields/syncRowGates.ts +0 -66
- package/src/react/fields/textInputControls.tsx +0 -238
- package/src/react/fields/useRowReorderDnd.ts +0 -78
- package/src/react/formStateHelpers.test.ts +0 -508
- package/src/react/formStateHelpers.ts +0 -381
- package/src/react/hooks/use-mobile.ts +0 -19
- package/src/react/icon-context.tsx +0 -60
- package/src/react/index.ts +0 -194
- package/src/react/layouts/SidebarLayout.tsx +0 -250
- package/src/react/layouts/TopbarLayout.tsx +0 -258
- package/src/react/navigate.tsx +0 -37
- package/src/react/onProviderSynced.test.ts +0 -90
- package/src/react/parseRecordEditUrl.test.ts +0 -122
- package/src/react/parseRecordEditUrl.ts +0 -94
- package/src/react/persistedState.ts +0 -40
- package/src/react/registry.ts +0 -48
- package/src/react/right-panel-registry.tsx +0 -47
- package/src/react/schemaRenderer/AlertRenderer.tsx +0 -112
- package/src/react/schemaRenderer/EntryRenderer.tsx +0 -501
- package/src/react/schemaRenderer/SectionRenderer.tsx +0 -120
- package/src/react/schemaRenderer/SimpleElements.tsx +0 -306
- package/src/react/schemaRenderer/TabsRenderer.tsx +0 -62
- package/src/react/schemaRenderer/WizardRenderer.tsx +0 -338
- package/src/react/schemaRenderer/action/ActionGroupTrigger.tsx +0 -177
- package/src/react/schemaRenderer/action/ActionModalDialog.tsx +0 -273
- package/src/react/schemaRenderer/action/ConfirmActionDialog.tsx +0 -61
- package/src/react/schemaRenderer/action/HandlerActionButton.tsx +0 -43
- package/src/react/schemaRenderer/action/MethodActionButton.tsx +0 -64
- package/src/react/schemaRenderer/action/buttons.tsx +0 -99
- package/src/react/schemaRenderer/action/helpers.ts +0 -140
- package/src/react/schemaRenderer/action/renderAction.tsx +0 -245
- package/src/react/schemaRenderer/columnFormat.ts +0 -65
- package/src/react/schemaRenderer/constants.ts +0 -50
- package/src/react/schemaRenderer/form/FormRenderer.tsx +0 -274
- package/src/react/schemaRenderer/form/renderField.tsx +0 -511
- package/src/react/schemaRenderer/helpers.tsx +0 -81
- package/src/react/schemaRenderer/table/CardsLayoutBody.tsx +0 -308
- package/src/react/schemaRenderer/table/TableRenderer.tsx +0 -123
- package/src/react/schemaRenderer/table/TableRendererBody.tsx +0 -974
- package/src/react/schemaRenderer/table/filters.tsx +0 -1233
- package/src/react/schemaRenderer/table/formatCell.tsx +0 -264
- package/src/react/schemaRenderer/table/links.tsx +0 -112
- package/src/react/schemaRenderer/table/renderRowActions.tsx +0 -52
- package/src/react/schemaRenderer/table/url.tsx +0 -143
- package/src/react/theme-preview/apply.ts +0 -99
- package/src/react/theme-preview/build-html.ts +0 -436
- package/src/react/ui/button.tsx +0 -51
- package/src/react/ui/calendar.tsx +0 -67
- package/src/react/ui/checkbox.tsx +0 -29
- package/src/react/ui/dialog.tsx +0 -108
- package/src/react/ui/dropdown-menu.tsx +0 -97
- package/src/react/ui/input.tsx +0 -20
- package/src/react/ui/label.tsx +0 -21
- package/src/react/ui/popover.tsx +0 -50
- package/src/react/ui/select.tsx +0 -169
- package/src/react/ui/separator.tsx +0 -25
- package/src/react/ui/sheet.tsx +0 -136
- package/src/react/ui/sidebar.tsx +0 -723
- package/src/react/ui/skeleton.tsx +0 -13
- package/src/react/ui/slider.tsx +0 -34
- package/src/react/ui/switch.tsx +0 -28
- package/src/react/ui/table.tsx +0 -105
- package/src/react/ui/tabs.tsx +0 -63
- package/src/react/ui/textarea.tsx +0 -18
- package/src/react/ui/tooltip.tsx +0 -64
- package/src/react/useResizableWidth.ts +0 -139
- package/src/react/utils.ts +0 -6
- package/src/react/widgetRegistry.test.ts +0 -43
- package/src/react/widgetRegistry.ts +0 -50
- package/src/react/widgets/StatsOverviewRenderer.tsx +0 -232
- package/src/react/widgets/TableWidgetRenderer.tsx +0 -231
- package/src/react/widgets/ViewRenderer.tsx +0 -71
- package/src/relationManagerData.test.ts +0 -1595
- package/src/richtext/index.ts +0 -8
- package/src/richtext/registry.ts +0 -89
- package/src/routes/globals.ts +0 -148
- package/src/routes/guard.test.ts +0 -325
- package/src/routes/helpers.ts +0 -704
- package/src/routes/pages.ts +0 -175
- package/src/routes/panel.ts +0 -204
- package/src/routes/relations.ts +0 -1243
- package/src/routes/resources.ts +0 -781
- package/src/routes/theme.ts +0 -91
- package/src/routes-nested-relations.test.ts +0 -676
- package/src/routes-relations.test.ts +0 -972
- package/src/routes.test.ts +0 -2027
- package/src/routes.ts +0 -303
- package/src/schema/Alert.test.ts +0 -109
- package/src/schema/Alert.ts +0 -131
- package/src/schema/Block.ts +0 -169
- package/src/schema/Breadcrumbs.ts +0 -40
- package/src/schema/Card.ts +0 -35
- package/src/schema/Divider.ts +0 -20
- package/src/schema/Element.ts +0 -219
- package/src/schema/EmptyState.test.ts +0 -37
- package/src/schema/EmptyState.ts +0 -63
- package/src/schema/Fieldset.ts +0 -43
- package/src/schema/Grid.ts +0 -43
- package/src/schema/Group.ts +0 -30
- package/src/schema/Heading.ts +0 -39
- package/src/schema/Html.ts +0 -67
- package/src/schema/Icon.ts +0 -54
- package/src/schema/Image.ts +0 -57
- package/src/schema/LinkTag.ts +0 -41
- package/src/schema/Markdown.ts +0 -85
- package/src/schema/MetaTag.ts +0 -41
- package/src/schema/RelationTabs.ts +0 -71
- package/src/schema/ScriptTag.ts +0 -55
- package/src/schema/Section.ts +0 -160
- package/src/schema/ServerDataElement.test.ts +0 -140
- package/src/schema/ServerDataElement.ts +0 -156
- package/src/schema/SlotComponent.test.ts +0 -77
- package/src/schema/SlotComponent.ts +0 -71
- package/src/schema/Split.ts +0 -50
- package/src/schema/Stat.test.ts +0 -118
- package/src/schema/Stat.ts +0 -154
- package/src/schema/StatsOverview.test.ts +0 -141
- package/src/schema/StatsOverview.ts +0 -119
- package/src/schema/StyleTag.ts +0 -35
- package/src/schema/TableWidget.test.ts +0 -297
- package/src/schema/TableWidget.ts +0 -289
- package/src/schema/Tabs.ts +0 -79
- package/src/schema/Text.ts +0 -58
- package/src/schema/UnorderedList.ts +0 -49
- package/src/schema/View.test.ts +0 -111
- package/src/schema/View.ts +0 -127
- package/src/schema/Wizard.ts +0 -220
- package/src/schema/containers.test.ts +0 -564
- package/src/schema/headTags.test.ts +0 -134
- package/src/schema/index.ts +0 -40
- package/src/schema/primes.test.ts +0 -269
- package/src/schema/resolveSchema.test.ts +0 -379
- package/src/schema/resolveSchema.ts +0 -917
- package/src/schema/sanitize.ts +0 -58
- package/src/search.test.ts +0 -446
- package/src/search.ts +0 -178
- package/src/sessionFilters.test.ts +0 -375
- package/src/sessionFilters.ts +0 -143
- package/src/slot-components/index.ts +0 -10
- package/src/slot-components/registry.ts +0 -56
- package/src/styles/file-upload.css +0 -13
- package/src/summarizers/Summarizer.test.ts +0 -84
- package/src/summarizers/Summarizer.ts +0 -123
- package/src/summarizers/index.ts +0 -11
- package/src/theme/base-colors.ts +0 -68
- package/src/theme/chart-colors.ts +0 -50
- package/src/theme/colors.ts +0 -447
- package/src/theme/generate-css.test.ts +0 -139
- package/src/theme/generate-css.ts +0 -44
- package/src/theme/generate-scale.test.ts +0 -106
- package/src/theme/generate-scale.ts +0 -97
- package/src/theme/icon-map.ts +0 -42
- package/src/theme/index.ts +0 -34
- package/src/theme/migrate.test.ts +0 -178
- package/src/theme/migrate.ts +0 -81
- package/src/theme/presets.ts +0 -135
- package/src/theme/radius.ts +0 -18
- package/src/theme/resolve.test.ts +0 -238
- package/src/theme/resolve.ts +0 -96
- package/src/theme/spacing.ts +0 -18
- package/src/theme/storage.test.ts +0 -126
- package/src/theme/storage.ts +0 -106
- package/src/theme/theme-colors.ts +0 -88
- package/src/theme/types.ts +0 -125
- package/src/uploads/UploadAdapter.ts +0 -35
- package/src/uploads/index.ts +0 -2
- package/src/uploads/localUpload.test.ts +0 -70
- package/src/uploads/localUpload.ts +0 -84
- package/src/validation/Validator.ts +0 -49
- package/src/validation/index.ts +0 -28
- package/src/validation/rules.ts +0 -78
- package/src/validation/runValidators.ts +0 -435
- package/src/validation/uniqueValidator.test.ts +0 -196
- package/src/validation/uniqueValidator.ts +0 -133
- package/src/validation/validators.test.ts +0 -268
- package/src/vite.test.ts +0 -184
- package/src/vite.ts +0 -787
- package/src/widgets/index.ts +0 -10
- package/src/widgets/registry.ts +0 -45
- package/src/widgets.test.ts +0 -592
- package/tsconfig.build.json +0 -11
- package/tsconfig.json +0 -4
- package/tsconfig.test.json +0 -10
- package/views/react/Dashboard.tsx +0 -27
- package/views/react/Resources/Form.tsx +0 -102
- package/views/react/Resources/Index.tsx +0 -49
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan #15 Phase D — `TableWidget` element tests.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it } from 'node:test'
|
|
6
|
-
import assert from 'node:assert/strict'
|
|
7
|
-
|
|
8
|
-
import { Column } from '../Column.js'
|
|
9
|
-
import { TableWidget } from './TableWidget.js'
|
|
10
|
-
import { resolveSchema, type RenderContext } from './resolveSchema.js'
|
|
11
|
-
import { isServerDataElement } from './ServerDataElement.js'
|
|
12
|
-
import type { ModelLike, ModelQuery } from '../orm/modelDefaults.js'
|
|
13
|
-
|
|
14
|
-
// ─── Test stubs ──────────────────────────────────────────────
|
|
15
|
-
|
|
16
|
-
class StubQuery implements ModelQuery {
|
|
17
|
-
public readonly ops: Array<{ op: string; args: unknown[] }> = []
|
|
18
|
-
constructor(private readonly rows: unknown[], private readonly total = rows.length) {}
|
|
19
|
-
where(...args: unknown[]): this { this.ops.push({ op: 'where', args }); return this }
|
|
20
|
-
orWhere(...args: unknown[]): this { this.ops.push({ op: 'orWhere', args }); return this }
|
|
21
|
-
orderBy(column: string, direction?: 'ASC' | 'DESC'): this {
|
|
22
|
-
this.ops.push({ op: 'orderBy', args: [column, direction] })
|
|
23
|
-
return this
|
|
24
|
-
}
|
|
25
|
-
async paginate(page: number, perPage?: number): Promise<{ data: unknown[]; total: number }> {
|
|
26
|
-
this.ops.push({ op: 'paginate', args: [page, perPage] })
|
|
27
|
-
return { data: this.rows, total: this.total }
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function stubModel(rows: unknown[]): ModelLike {
|
|
32
|
-
return {
|
|
33
|
-
async find() { return undefined },
|
|
34
|
-
async create() { return undefined },
|
|
35
|
-
async update() { return undefined },
|
|
36
|
-
async delete() { return undefined },
|
|
37
|
-
query() { return new StubQuery(rows) },
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ─── Tests ──────────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
describe('TableWidget element', () => {
|
|
44
|
-
describe('factory + identity', () => {
|
|
45
|
-
it('TableWidget.make() returns an instance', () => {
|
|
46
|
-
const w = TableWidget.make('recent')
|
|
47
|
-
assert.ok(w instanceof TableWidget)
|
|
48
|
-
assert.equal(w.getType(), 'tableWidget')
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('falls back to subclass class name when no id passed', () => {
|
|
52
|
-
class RecentPosts extends TableWidget {}
|
|
53
|
-
assert.equal(RecentPosts.make().getId(), 'RecentPosts')
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('explicit id wins over class name', () => {
|
|
57
|
-
class RecentPosts extends TableWidget {}
|
|
58
|
-
assert.equal(RecentPosts.make('explicit').getId(), 'explicit')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('is a ServerDataElement', () => {
|
|
62
|
-
assert.equal(isServerDataElement(TableWidget.make('a')), true)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('lazy default = true (inherited)', () => {
|
|
66
|
-
assert.equal(TableWidget.make('a').isLazy(), true)
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
describe('label / viewAllUrl', () => {
|
|
71
|
-
it('instance label setter wins over static', () => {
|
|
72
|
-
class Static extends TableWidget {
|
|
73
|
-
static override label = 'Static label'
|
|
74
|
-
}
|
|
75
|
-
const w = Static.make().label('Instance label')
|
|
76
|
-
assert.equal(w.getLabel(), 'Instance label')
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
it('static label is the fallback', () => {
|
|
80
|
-
class Static extends TableWidget {
|
|
81
|
-
static override label = 'Static label'
|
|
82
|
-
}
|
|
83
|
-
assert.equal(Static.make().getLabel(), 'Static label')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('returns undefined when neither set', () => {
|
|
87
|
-
assert.equal(TableWidget.make('a').getLabel(), undefined)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('viewAllUrl: instance wins over static', () => {
|
|
91
|
-
class Static extends TableWidget {
|
|
92
|
-
static override viewAllUrl = '/static'
|
|
93
|
-
}
|
|
94
|
-
assert.equal(Static.make().viewAllUrl('/instance').getViewAllUrl(), '/instance')
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
it('viewAllUrl: static is the fallback', () => {
|
|
98
|
-
class Static extends TableWidget {
|
|
99
|
-
static override viewAllUrl = '/static'
|
|
100
|
-
}
|
|
101
|
-
assert.equal(Static.make().getViewAllUrl(), '/static')
|
|
102
|
-
})
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
describe('columns', () => {
|
|
106
|
-
it('instance columns wins over static factory', () => {
|
|
107
|
-
class Static extends TableWidget {
|
|
108
|
-
static override columns = () => [Column.make('static')]
|
|
109
|
-
}
|
|
110
|
-
const w = Static.make().columns([Column.make('instance')])
|
|
111
|
-
assert.equal(w.getColumns().length, 1)
|
|
112
|
-
assert.equal(w.getColumns()[0]!.name, 'instance')
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('static columns() factory is the fallback', () => {
|
|
116
|
-
class Static extends TableWidget {
|
|
117
|
-
static override columns = () => [Column.make('a'), Column.make('b')]
|
|
118
|
-
}
|
|
119
|
-
const cols = Static.make().getColumns()
|
|
120
|
-
assert.equal(cols.length, 2)
|
|
121
|
-
assert.equal(cols[0]!.name, 'a')
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
it('returns [] when no columns configured', () => {
|
|
125
|
-
assert.deepEqual(TableWidget.make('a').getColumns(), [])
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
describe('toMeta()', () => {
|
|
130
|
-
it('emits type=tableWidget with empty columns by default', async () => {
|
|
131
|
-
const [meta] = await resolveSchema([TableWidget.make('a')])
|
|
132
|
-
assert.equal(meta!.type, 'tableWidget')
|
|
133
|
-
assert.deepEqual(meta!['columns'], [])
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('serializes columns inline (not as children)', async () => {
|
|
137
|
-
const [meta] = await resolveSchema([
|
|
138
|
-
TableWidget.make('a').columns([Column.make('title').label('Title')]),
|
|
139
|
-
])
|
|
140
|
-
assert.equal(Array.isArray(meta!['columns']), true)
|
|
141
|
-
assert.equal((meta!['columns'] as unknown[]).length, 1)
|
|
142
|
-
assert.equal(((meta!['columns'] as Array<{ name: string; label: string }>)[0])!.label, 'Title')
|
|
143
|
-
assert.equal(meta!.children, undefined)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
it('emits label + viewAllUrl when set', async () => {
|
|
147
|
-
const [meta] = await resolveSchema([
|
|
148
|
-
TableWidget.make('a').label('Recent').viewAllUrl('/all'),
|
|
149
|
-
])
|
|
150
|
-
assert.equal(meta!['label'], 'Recent')
|
|
151
|
-
assert.equal(meta!['viewAllUrl'], '/all')
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
it('omits label + viewAllUrl when unset', async () => {
|
|
155
|
-
const [meta] = await resolveSchema([TableWidget.make('a')])
|
|
156
|
-
assert.equal(meta!['label'], undefined)
|
|
157
|
-
assert.equal(meta!['viewAllUrl'], undefined)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('serverData wire-shape stamps land on top', async () => {
|
|
161
|
-
class W extends TableWidget {}
|
|
162
|
-
const w = W.make().poll(60).lazy(false)
|
|
163
|
-
const [meta] = await resolveSchema([w])
|
|
164
|
-
assert.equal(meta!['serverData'], true)
|
|
165
|
-
assert.equal(meta!['id'], 'W')
|
|
166
|
-
assert.equal(meta!['poll'], 60)
|
|
167
|
-
assert.equal(meta!['lazy'], false)
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
describe('resolveServerData() — fluent records', () => {
|
|
172
|
-
it('runs the instance .records(fn) hook', async () => {
|
|
173
|
-
const w = TableWidget.make('a').records(async () => ({
|
|
174
|
-
rows: [{ id: 1, title: 'Hello' }],
|
|
175
|
-
total: 1,
|
|
176
|
-
}))
|
|
177
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
178
|
-
assert.deepEqual(data, { rows: [{ id: 1, title: 'Hello' }], total: 1 })
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
it('omits total when records() did', async () => {
|
|
182
|
-
const w = TableWidget.make('a').records(async () => ({ rows: [{ id: 1 }] }))
|
|
183
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
184
|
-
assert.deepEqual(data, { rows: [{ id: 1 }] })
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
it('passes the render context to records()', async () => {
|
|
188
|
-
let received: unknown = null
|
|
189
|
-
const w = TableWidget.make('a').records(async (ctx) => {
|
|
190
|
-
received = ctx
|
|
191
|
-
return { rows: [] }
|
|
192
|
-
})
|
|
193
|
-
await w.resolveServerData({ user: { id: 1 } } as RenderContext)
|
|
194
|
-
assert.deepEqual(received, { user: { id: 1 } })
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
describe('resolveServerData() — subclass records', () => {
|
|
199
|
-
it('subclass static records() runs when no instance setter', async () => {
|
|
200
|
-
class Sub extends TableWidget {
|
|
201
|
-
static override async records() {
|
|
202
|
-
return { rows: [{ id: 1 }], total: 1 }
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const data = await Sub.make().resolveServerData({} as RenderContext)
|
|
206
|
-
assert.deepEqual(data, { rows: [{ id: 1 }], total: 1 })
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
it('instance .records() overrides static records()', async () => {
|
|
210
|
-
class Sub extends TableWidget {
|
|
211
|
-
static override async records() {
|
|
212
|
-
return { rows: [{ id: 'static' }] }
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const w = Sub.make().records(async () => ({ rows: [{ id: 'instance' }] }))
|
|
216
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
217
|
-
assert.deepEqual(data, { rows: [{ id: 'instance' }] })
|
|
218
|
-
})
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
describe('resolveServerData() — model + query', () => {
|
|
222
|
-
it('default model path uses paginate(1, 5)', async () => {
|
|
223
|
-
const M = stubModel([{ id: 1 }, { id: 2 }])
|
|
224
|
-
const w = TableWidget.make('a').model(M)
|
|
225
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
226
|
-
assert.deepEqual(data.rows, [{ id: 1 }, { id: 2 }])
|
|
227
|
-
assert.equal(data.total, 2)
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
it('custom .query(fn) drives the model query', async () => {
|
|
231
|
-
const M = stubModel([{ id: 1 }])
|
|
232
|
-
let saw: ModelQuery | undefined
|
|
233
|
-
const w = TableWidget.make('a').model(M).query(async (q) => {
|
|
234
|
-
saw = q
|
|
235
|
-
return q.orderBy('id', 'DESC').paginate(1, 3)
|
|
236
|
-
})
|
|
237
|
-
await w.resolveServerData({} as RenderContext)
|
|
238
|
-
const ops = (saw as unknown as StubQuery).ops
|
|
239
|
-
assert.equal(ops[0]!.op, 'orderBy')
|
|
240
|
-
assert.equal(ops[1]!.op, 'paginate')
|
|
241
|
-
assert.deepEqual(ops[1]!.args, [1, 3])
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
it('static query() on subclass is honored when instance has none', async () => {
|
|
245
|
-
const M = stubModel([{ id: 99 }])
|
|
246
|
-
class Sub extends TableWidget {
|
|
247
|
-
static override model = M
|
|
248
|
-
static override query = async (q: ModelQuery) =>
|
|
249
|
-
q.orderBy('createdAt', 'DESC').paginate(1, 7)
|
|
250
|
-
}
|
|
251
|
-
const w = Sub.make()
|
|
252
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
253
|
-
assert.deepEqual(data.rows, [{ id: 99 }])
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
it('throws when no records source is configured', async () => {
|
|
257
|
-
await assert.rejects(
|
|
258
|
-
() => TableWidget.make('a').resolveServerData({} as RenderContext),
|
|
259
|
-
/no rows source/,
|
|
260
|
-
)
|
|
261
|
-
})
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
describe('resolveServerData() — formatStateUsing per row', () => {
|
|
265
|
-
it('runs server-side formatters and stamps row._formatted', async () => {
|
|
266
|
-
const w = TableWidget.make('a')
|
|
267
|
-
.columns([
|
|
268
|
-
Column.make('title').formatStateUsing((value) => `> ${value}`),
|
|
269
|
-
Column.make('plain'),
|
|
270
|
-
])
|
|
271
|
-
.records(async () => ({
|
|
272
|
-
rows: [{ title: 'Hello', plain: 'untouched' }],
|
|
273
|
-
}))
|
|
274
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
275
|
-
const row = data.rows[0]!
|
|
276
|
-
assert.deepEqual(row['_formatted'], { title: '> Hello' })
|
|
277
|
-
assert.equal(row['plain'], 'untouched')
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
it('skipped entirely when no column has a formatter', async () => {
|
|
281
|
-
const w = TableWidget.make('a')
|
|
282
|
-
.columns([Column.make('title')])
|
|
283
|
-
.records(async () => ({ rows: [{ title: 'Hello' }] }))
|
|
284
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
285
|
-
assert.equal(data.rows[0]!['_formatted'], undefined)
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
it('throwing formatter falls back silently', async () => {
|
|
289
|
-
const w = TableWidget.make('a')
|
|
290
|
-
.columns([Column.make('title').formatStateUsing(() => { throw new Error('boom') })])
|
|
291
|
-
.records(async () => ({ rows: [{ title: 'Hello' }] }))
|
|
292
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
293
|
-
// No `title` key on `_formatted` — renderer falls back to raw value.
|
|
294
|
-
assert.deepEqual(data.rows[0]!['_formatted'], {})
|
|
295
|
-
})
|
|
296
|
-
})
|
|
297
|
-
})
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { ServerDataElement } from './ServerDataElement.js'
|
|
2
|
-
import type { RenderContext } from './resolveSchema.js'
|
|
3
|
-
import { Column, type ColumnMeta } from '../Column.js'
|
|
4
|
-
import {
|
|
5
|
-
type ModelLike,
|
|
6
|
-
type ModelQuery,
|
|
7
|
-
} from '../orm/modelDefaults.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Plan #15 Phase D — `TableWidget` is the slim-table dashboard widget.
|
|
11
|
-
* Mirrors Filament's `Filament\Widgets\TableWidget`: a dashboard tile
|
|
12
|
-
* that surfaces a small list of records (e.g. "5 newest posts") without
|
|
13
|
-
* the full Resource list-page chrome (no filters, no bulk actions, no
|
|
14
|
-
* pagination, no search).
|
|
15
|
-
*
|
|
16
|
-
* Distinct from the schema-element `Table` (`elements/Table.ts`) — that
|
|
17
|
-
* one drives Resource list pages and carries the full surface. The
|
|
18
|
-
* widget renders a stripped-down `<table>` paint and reads its rows from
|
|
19
|
-
* `_widgetData[id]`.
|
|
20
|
-
*
|
|
21
|
-
* **Subclass form** (primary):
|
|
22
|
-
*
|
|
23
|
-
* import { TableWidget } from '@pilotiq/pilotiq'
|
|
24
|
-
* import { TextColumn } from '@pilotiq/pilotiq/columns'
|
|
25
|
-
* import { Post } from '#models'
|
|
26
|
-
*
|
|
27
|
-
* export class RecentPosts extends TableWidget {
|
|
28
|
-
* static override label = 'Recent posts'
|
|
29
|
-
* static override model = Post
|
|
30
|
-
* static override viewAllUrl = '/admin/posts'
|
|
31
|
-
* static override async query(q) {
|
|
32
|
-
* return q.orderBy('createdAt', 'desc').paginate(1, 5)
|
|
33
|
-
* }
|
|
34
|
-
* static override columns() {
|
|
35
|
-
* return [
|
|
36
|
-
* TextColumn.make('title').limit(40),
|
|
37
|
-
* TextColumn.make('createdAt').dateTime(),
|
|
38
|
-
* ]
|
|
39
|
-
* }
|
|
40
|
-
* }
|
|
41
|
-
*
|
|
42
|
-
* **Fluent form** — useful for one-off cases:
|
|
43
|
-
*
|
|
44
|
-
* TableWidget.make('recent-posts')
|
|
45
|
-
* .label('Recent posts')
|
|
46
|
-
* .columns([Column.make('title')])
|
|
47
|
-
* .records(async () => ({ rows: [{ title: 'Hi' }], total: 1 }))
|
|
48
|
-
* .viewAllUrl('/admin/posts')
|
|
49
|
-
*
|
|
50
|
-
* Wire-shape:
|
|
51
|
-
* meta: { type: 'tableWidget', label?, viewAllUrl?, columns: ColumnMeta[],
|
|
52
|
-
* serverData, id, lazy[, poll] }
|
|
53
|
-
* _widgetData[id]: { rows: Record<string, unknown>[]; total?: number }
|
|
54
|
-
*
|
|
55
|
-
* Lazy default = true (inherited from `ServerDataElement`).
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
/** Result returned by `records()` — rows plus optional total. The total
|
|
59
|
-
* is informational only in v1 (no pagination in the slim renderer);
|
|
60
|
-
* reserved for future "View all (24)" badge sugar. */
|
|
61
|
-
export interface TableWidgetRecordsResult {
|
|
62
|
-
rows: Record<string, unknown>[]
|
|
63
|
-
total?: number
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export type TableWidgetRecordsHandler = (
|
|
67
|
-
ctx: RenderContext,
|
|
68
|
-
) => TableWidgetRecordsResult | Promise<TableWidgetRecordsResult>
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Subclass-form `query(q)` hook — receives a `ModelQuery` from
|
|
72
|
-
* `static model.query()` and returns a `Promise<{ data, total }>`. The
|
|
73
|
-
* `paginate()` call lives inside the hook so users control limit (e.g.
|
|
74
|
-
* `q.orderBy(...).paginate(1, 5)` for "5 newest").
|
|
75
|
-
*
|
|
76
|
-
* Returning the bare query (without `paginate()`) is a programming error
|
|
77
|
-
* — the widget needs an awaited result, not another query builder.
|
|
78
|
-
*/
|
|
79
|
-
export type TableWidgetQueryHandler = (
|
|
80
|
-
q: ModelQuery,
|
|
81
|
-
) => Promise<{ data: unknown[]; total: number }>
|
|
82
|
-
|
|
83
|
-
export interface TableWidgetPayload {
|
|
84
|
-
rows: Record<string, unknown>[]
|
|
85
|
-
total?: number
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export class TableWidget extends ServerDataElement {
|
|
89
|
-
// ─── Subclass-time defaults ──────────────────────────────
|
|
90
|
-
/** Heading rendered above the table. Falls back to the class name when
|
|
91
|
-
* unset and `viewAllUrl` is set (the link needs visible chrome). */
|
|
92
|
-
static label?: string
|
|
93
|
-
/** Optional ORM model — when set, default `records()` does
|
|
94
|
-
* `M.query()` then runs the configured `query()` hook (which must
|
|
95
|
-
* paginate to bound the row count). */
|
|
96
|
-
static model?: ModelLike
|
|
97
|
-
/** Optional "View all →" link href shown in the widget header. */
|
|
98
|
-
static viewAllUrl?: string
|
|
99
|
-
/** Subclass-form column factory. Called once per resolve; instance
|
|
100
|
-
* setter wins. */
|
|
101
|
-
static columns?: () => Column[]
|
|
102
|
-
/** Subclass-form query hook (model-driven path). Falls back to a
|
|
103
|
-
* bare `paginate(1, 5)` when unset. */
|
|
104
|
-
static query?: TableWidgetQueryHandler
|
|
105
|
-
/** Subclass-form full-records override. When set, takes precedence
|
|
106
|
-
* over `model + query`. */
|
|
107
|
-
static records?: TableWidgetRecordsHandler
|
|
108
|
-
|
|
109
|
-
// ─── Instance state (fluent overrides) ──────────────────
|
|
110
|
-
private _label?: string
|
|
111
|
-
private _model?: ModelLike
|
|
112
|
-
private _viewAllUrl?: string
|
|
113
|
-
private _columns?: Column[]
|
|
114
|
-
private _query?: TableWidgetQueryHandler
|
|
115
|
-
private _records?: TableWidgetRecordsHandler
|
|
116
|
-
|
|
117
|
-
constructor(id?: string) {
|
|
118
|
-
super()
|
|
119
|
-
if (id) this._id = id
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
static make(this: new (id?: string) => TableWidget, id?: string): TableWidget {
|
|
123
|
-
return new this(id)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// ─── Fluent setters ──────────────────────────────────────
|
|
127
|
-
|
|
128
|
-
/** Heading rendered above the table. */
|
|
129
|
-
label(text: string): this {
|
|
130
|
-
this._label = text
|
|
131
|
-
return this
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/** Bind a `ModelLike` for the default model-driven records loader. */
|
|
135
|
-
model(M: ModelLike): this {
|
|
136
|
-
this._model = M
|
|
137
|
-
return this
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/** Custom query hook — receives `M.query()` and must return a
|
|
141
|
-
* `paginate()` promise. Composes with `.model(M)`. */
|
|
142
|
-
query(fn: TableWidgetQueryHandler): this {
|
|
143
|
-
this._query = fn
|
|
144
|
-
return this
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** Full records override — fully replaces the `model + query` path. */
|
|
148
|
-
records(fn: TableWidgetRecordsHandler): this {
|
|
149
|
-
this._records = fn
|
|
150
|
-
return this
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** Column children. The renderer reads label / format / columnType /
|
|
154
|
-
* formatter from each column's resolved meta — same shape as the
|
|
155
|
-
* Resource list table. Columns are serialized inline under
|
|
156
|
-
* `meta.columns` (not under `meta.children`) so the resolver doesn't
|
|
157
|
-
* treat them as standalone nodes. */
|
|
158
|
-
columns(cols: Column[]): this {
|
|
159
|
-
this._columns = cols
|
|
160
|
-
return this
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** "View all →" link href. */
|
|
164
|
-
viewAllUrl(href: string): this {
|
|
165
|
-
this._viewAllUrl = href
|
|
166
|
-
return this
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// ─── Getters ─────────────────────────────────────────────
|
|
170
|
-
|
|
171
|
-
/** Effective label. Instance setter wins; static is the fallback. */
|
|
172
|
-
getLabel(): string | undefined {
|
|
173
|
-
if (this._label !== undefined) return this._label
|
|
174
|
-
const ctor = this.constructor as { label?: string }
|
|
175
|
-
return ctor.label
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** Effective viewAllUrl. */
|
|
179
|
-
getViewAllUrl(): string | undefined {
|
|
180
|
-
if (this._viewAllUrl !== undefined) return this._viewAllUrl
|
|
181
|
-
const ctor = this.constructor as { viewAllUrl?: string }
|
|
182
|
-
return ctor.viewAllUrl
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Effective model. */
|
|
186
|
-
getModel(): ModelLike | undefined {
|
|
187
|
-
if (this._model !== undefined) return this._model
|
|
188
|
-
const ctor = this.constructor as { model?: ModelLike }
|
|
189
|
-
return ctor.model
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** Effective columns. Instance setter wins; static factory is the
|
|
193
|
-
* fallback. Empty array when neither is set. */
|
|
194
|
-
getColumns(): Column[] {
|
|
195
|
-
if (this._columns !== undefined) return this._columns
|
|
196
|
-
const ctor = this.constructor as { columns?: () => Column[] }
|
|
197
|
-
if (typeof ctor.columns === 'function') {
|
|
198
|
-
const out = ctor.columns()
|
|
199
|
-
this._columns = out
|
|
200
|
-
return out
|
|
201
|
-
}
|
|
202
|
-
return []
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
override getType(): string { return 'tableWidget' }
|
|
206
|
-
|
|
207
|
-
override toMeta(): Record<string, unknown> {
|
|
208
|
-
const meta: Record<string, unknown> = { type: 'tableWidget' as const }
|
|
209
|
-
const label = this.getLabel()
|
|
210
|
-
if (label !== undefined) meta['label'] = label
|
|
211
|
-
const url = this.getViewAllUrl()
|
|
212
|
-
if (url !== undefined) meta['viewAllUrl'] = url
|
|
213
|
-
meta['columns'] = this.getColumns().map(c => c.toMeta() as ColumnMeta)
|
|
214
|
-
return meta
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// ─── Server-data resolve ────────────────────────────────
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Run the configured row loader. Falls back through:
|
|
221
|
-
* 1. instance `.records(fn)` setter,
|
|
222
|
-
* 2. subclass `static records(ctx)`,
|
|
223
|
-
* 3. instance `.model(M) + .query(fn)`,
|
|
224
|
-
* 4. subclass `static model + static query?(q)`,
|
|
225
|
-
* 5. error — at least one path must be configured.
|
|
226
|
-
*
|
|
227
|
-
* The default `query` hook (when only `model` is set) is
|
|
228
|
-
* `q => q.paginate(1, 5)`. Override on the subclass for "10 newest"
|
|
229
|
-
* etc.
|
|
230
|
-
*/
|
|
231
|
-
async resolveServerData(ctx: RenderContext): Promise<TableWidgetPayload> {
|
|
232
|
-
let payload: TableWidgetPayload
|
|
233
|
-
|
|
234
|
-
if (this._records) {
|
|
235
|
-
payload = this.normalizeResult(await this._records(ctx))
|
|
236
|
-
} else {
|
|
237
|
-
const ctor = this.constructor as { records?: TableWidgetRecordsHandler }
|
|
238
|
-
if (ctor.records) {
|
|
239
|
-
payload = this.normalizeResult(await ctor.records(ctx))
|
|
240
|
-
} else {
|
|
241
|
-
const M = this.getModel()
|
|
242
|
-
if (!M) {
|
|
243
|
-
throw new Error(
|
|
244
|
-
`[Pilotiq] TableWidget "${this.getId()}" has no rows source — call .records(fn), ` +
|
|
245
|
-
`.model(M).query(fn), or set static model / records / columns on the subclass.`,
|
|
246
|
-
)
|
|
247
|
-
}
|
|
248
|
-
const q = M.query()
|
|
249
|
-
const fn = this._query ?? (this.constructor as { query?: TableWidgetQueryHandler }).query ?? defaultQueryHook
|
|
250
|
-
const result = await fn(q)
|
|
251
|
-
payload = result.total !== undefined
|
|
252
|
-
? { rows: (result.data as Record<string, unknown>[]) ?? [], total: result.total }
|
|
253
|
-
: { rows: (result.data as Record<string, unknown>[]) ?? [] }
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Per-row server-side `formatStateUsing` — same convention as the
|
|
258
|
-
// full `Table` (`row._formatted[colName]`). Skipped when no column
|
|
259
|
-
// has a formatter so we don't allocate per-row in the common case.
|
|
260
|
-
const columnsWithFormatter = this.getColumns().filter(c => c.hasFormatter())
|
|
261
|
-
if (columnsWithFormatter.length > 0) {
|
|
262
|
-
payload.rows = payload.rows.map(row => {
|
|
263
|
-
const formatted: Record<string, string> = {}
|
|
264
|
-
for (const col of columnsWithFormatter) {
|
|
265
|
-
const fn = col.getFormatStateHandler()
|
|
266
|
-
if (!fn) continue
|
|
267
|
-
try { formatted[col.name] = fn(row[col.name], row) }
|
|
268
|
-
catch { /* fall back to raw value in renderer */ }
|
|
269
|
-
}
|
|
270
|
-
return { ...row, _formatted: formatted }
|
|
271
|
-
})
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return payload
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
private normalizeResult(r: TableWidgetRecordsResult): TableWidgetPayload {
|
|
278
|
-
return r.total !== undefined
|
|
279
|
-
? { rows: r.rows, total: r.total }
|
|
280
|
-
: { rows: r.rows }
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/** Default query hook — paginate to the first 5 rows. Users override on
|
|
285
|
-
* the subclass (`static async query(q) { return q.orderBy(...).paginate(1, 10) }`)
|
|
286
|
-
* or via the instance setter for limits / sorts. */
|
|
287
|
-
function defaultQueryHook(q: ModelQuery): Promise<{ data: unknown[]; total: number }> {
|
|
288
|
-
return q.paginate(1, 5)
|
|
289
|
-
}
|
package/src/schema/Tabs.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Element } from './Element.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Single tab within a `Tabs` container. Holds a label, optional icon/badge,
|
|
5
|
-
* and a list of child Elements. Resolves to its own meta entry inside the
|
|
6
|
-
* parent's children array.
|
|
7
|
-
*/
|
|
8
|
-
export class Tab extends Element {
|
|
9
|
-
private _icon?: string
|
|
10
|
-
private _badge?: string
|
|
11
|
-
|
|
12
|
-
private constructor(private _label: string) {
|
|
13
|
-
super()
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static make(label: string): Tab {
|
|
17
|
-
return new Tab(label)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
icon(i: string): this { this._icon = i; return this }
|
|
21
|
-
badge(b: string): this { this._badge = b; return this }
|
|
22
|
-
|
|
23
|
-
schema(elements: Element[]): this {
|
|
24
|
-
this._children = elements
|
|
25
|
-
return this
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
getType(): string { return 'tab' }
|
|
29
|
-
|
|
30
|
-
toMeta(): Record<string, unknown> {
|
|
31
|
-
return {
|
|
32
|
-
type: 'tab' as const,
|
|
33
|
-
label: this._label,
|
|
34
|
-
...(this._icon ? { icon: this._icon } : {}),
|
|
35
|
-
...(this._badge ? { badge: this._badge } : {}),
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type TabsVariant = 'pills' | 'underline'
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Multi-tab container. Children are `Tab` instances; each Tab has its own
|
|
44
|
-
* children rendered when its tab is active. Mirrors panels' `Tabs` element
|
|
45
|
-
* for the static case (model-backed and array-backed Tabs are a future
|
|
46
|
-
* extension).
|
|
47
|
-
*/
|
|
48
|
-
export class Tabs extends Element {
|
|
49
|
-
private _variant: TabsVariant = 'pills'
|
|
50
|
-
|
|
51
|
-
private constructor() {
|
|
52
|
-
super()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
static make(): Tabs {
|
|
56
|
-
return new Tabs()
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** Set the tab list. Each entry is a `Tab` instance with its own schema. */
|
|
60
|
-
tabs(tabs: Tab[]): this {
|
|
61
|
-
this._children = tabs
|
|
62
|
-
return this
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Visual style. `'pills'` (default) — shadcn pill background with sliding
|
|
67
|
-
* indicator. `'underline'` — bottom border on active tab.
|
|
68
|
-
*/
|
|
69
|
-
variant(v: TabsVariant): this {
|
|
70
|
-
this._variant = v
|
|
71
|
-
return this
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getType(): string { return 'tabs' }
|
|
75
|
-
|
|
76
|
-
toMeta(): Record<string, unknown> {
|
|
77
|
-
return { type: 'tabs' as const, variant: this._variant }
|
|
78
|
-
}
|
|
79
|
-
}
|