@pilotiq/pilotiq 0.24.1 → 0.24.2
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 +33 -0
- package/boost/guidelines.md +566 -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/package.json +6 -1
- 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
package/src/schema/Stat.test.ts
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan #15 Phase B — `Stat` value-object surface tests.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it } from 'node:test'
|
|
6
|
-
import assert from 'node:assert/strict'
|
|
7
|
-
|
|
8
|
-
import { Stat } from './Stat.js'
|
|
9
|
-
|
|
10
|
-
describe('Stat fluent surface', () => {
|
|
11
|
-
it('Stat.make(label) returns an instance whose meta carries the label', () => {
|
|
12
|
-
const meta = Stat.make('Users').toMeta()
|
|
13
|
-
assert.equal(meta.label, 'Users')
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
it('omits unset optional keys (compact wire)', () => {
|
|
17
|
-
const meta = Stat.make('Users').toMeta()
|
|
18
|
-
assert.deepEqual(Object.keys(meta).sort(), ['label'])
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('value(n) emits a numeric value', () => {
|
|
22
|
-
const meta = Stat.make('Users').value(42).toMeta()
|
|
23
|
-
assert.equal(meta.value, 42)
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('value(string) emits a string value (e.g. preformatted currency)', () => {
|
|
27
|
-
const meta = Stat.make('Revenue').value('$1,234').toMeta()
|
|
28
|
-
assert.equal(meta.value, '$1,234')
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('value(undefined) round-trips as null (renderer placeholder)', () => {
|
|
32
|
-
const meta = Stat.make('Users').value(undefined).toMeta()
|
|
33
|
-
assert.equal(meta.value, null)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('value(null) emits null', () => {
|
|
37
|
-
const meta = Stat.make('Users').value(null).toMeta()
|
|
38
|
-
assert.equal(meta.value, null)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('description() emits the supplementary line', () => {
|
|
42
|
-
const meta = Stat.make('Users').description('+12%').toMeta()
|
|
43
|
-
assert.equal(meta.description, '+12%')
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
it('descriptionIcon(name) defaults to position=after', () => {
|
|
47
|
-
const meta = Stat.make('Users').descriptionIcon('trending-up').toMeta()
|
|
48
|
-
assert.deepEqual(meta.descriptionIcon, { name: 'trending-up', position: 'after' })
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
it('descriptionIcon(name, "before") preserves the position', () => {
|
|
52
|
-
const meta = Stat.make('Users').descriptionIcon('trending-up', 'before').toMeta()
|
|
53
|
-
assert.deepEqual(meta.descriptionIcon, { name: 'trending-up', position: 'before' })
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('icon(name) emits the main icon', () => {
|
|
57
|
-
const meta = Stat.make('Users').icon('users').toMeta()
|
|
58
|
-
assert.equal(meta.icon, 'users')
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
it('color(c) emits the color preset', () => {
|
|
62
|
-
const meta = Stat.make('Users').color('success').toMeta()
|
|
63
|
-
assert.equal(meta.color, 'success')
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
it('chart([…]) emits a copy of the array (no aliasing)', () => {
|
|
67
|
-
const series = [1, 2, 3]
|
|
68
|
-
const stat = Stat.make('Users').chart(series)
|
|
69
|
-
series.push(99)
|
|
70
|
-
assert.deepEqual(stat.toMeta().chart, [1, 2, 3])
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('url(href) emits the URL', () => {
|
|
74
|
-
const meta = Stat.make('Users').url('/admin/users').toMeta()
|
|
75
|
-
assert.equal(meta.url, '/admin/users')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
it('openUrlInNewTab() defaults to true', () => {
|
|
79
|
-
const meta = Stat.make('Users').url('/x').openUrlInNewTab().toMeta()
|
|
80
|
-
assert.equal(meta.openInNewTab, true)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('openUrlInNewTab(false) opts back out', () => {
|
|
84
|
-
const meta = Stat.make('Users').url('/x').openUrlInNewTab(false).toMeta()
|
|
85
|
-
assert.equal(meta.openInNewTab, false)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('extraAttributes spreads onto meta as-is', () => {
|
|
89
|
-
const meta = Stat.make('Users').extraAttributes({ 'data-id': '1', 'aria-label': 'Users' }).toMeta()
|
|
90
|
-
assert.deepEqual(meta.extraAttributes, { 'data-id': '1', 'aria-label': 'Users' })
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('chained setters compose into a single meta', () => {
|
|
94
|
-
const meta = Stat.make('Users')
|
|
95
|
-
.value(1234)
|
|
96
|
-
.description('+12%')
|
|
97
|
-
.descriptionIcon('trending-up', 'before')
|
|
98
|
-
.icon('users')
|
|
99
|
-
.color('primary')
|
|
100
|
-
.chart([1, 2, 3, 4, 5])
|
|
101
|
-
.url('/admin/users')
|
|
102
|
-
.openUrlInNewTab()
|
|
103
|
-
.extraAttributes({ 'data-test': 'users-stat' })
|
|
104
|
-
.toMeta()
|
|
105
|
-
assert.deepEqual(meta, {
|
|
106
|
-
label: 'Users',
|
|
107
|
-
value: 1234,
|
|
108
|
-
description: '+12%',
|
|
109
|
-
descriptionIcon: { name: 'trending-up', position: 'before' },
|
|
110
|
-
icon: 'users',
|
|
111
|
-
color: 'primary',
|
|
112
|
-
chart: [1, 2, 3, 4, 5],
|
|
113
|
-
url: '/admin/users',
|
|
114
|
-
openInNewTab: true,
|
|
115
|
-
extraAttributes: { 'data-test': 'users-stat' },
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
})
|
package/src/schema/Stat.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan #15 Phase B — `Stat` is the fluent value object emitted by
|
|
3
|
-
* `StatsOverview.getStats(ctx)`. It does NOT extend Element — it has no
|
|
4
|
-
* place in the schema tree on its own. `StatsOverview.resolveServerData`
|
|
5
|
-
* collects the array of Stats and ships them as JSON-clean
|
|
6
|
-
* `StatMeta[]` payloads under `_widgetData[id]`.
|
|
7
|
-
*
|
|
8
|
-
* Stat.make('Users')
|
|
9
|
-
* .value(await User.query().count())
|
|
10
|
-
* .description('+12% this month')
|
|
11
|
-
* .descriptionIcon('trending-up', 'before')
|
|
12
|
-
* .icon('users')
|
|
13
|
-
* .color('success')
|
|
14
|
-
* .chart([12, 4, 8, 15, 22, 18, 30]) // sparkline
|
|
15
|
-
* .url('/admin/users').openUrlInNewTab()
|
|
16
|
-
*
|
|
17
|
-
* Surface mirrors Filament v5's `Stat` 1:1, modulo TS naming
|
|
18
|
-
* (`openUrlInNewTab(true)` not `->openUrlInNewTab()`).
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/** Color preset. Mirrors `TabBadgeColor` so a "Users · 5,234" stat can
|
|
22
|
-
* be tinted with the same palette as the rest of the panel chrome. */
|
|
23
|
-
export type StatColor =
|
|
24
|
-
| 'default'
|
|
25
|
-
| 'primary'
|
|
26
|
-
| 'success'
|
|
27
|
-
| 'warning'
|
|
28
|
-
| 'destructive'
|
|
29
|
-
| 'info'
|
|
30
|
-
|
|
31
|
-
/** Position for the optional `descriptionIcon`. Matches Filament's
|
|
32
|
-
* `IconPosition::Before / After` enum values. */
|
|
33
|
-
export type StatDescriptionIconPosition = 'before' | 'after'
|
|
34
|
-
|
|
35
|
-
export interface StatDescriptionIcon {
|
|
36
|
-
name: string
|
|
37
|
-
position: StatDescriptionIconPosition
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* JSON-clean payload shape — what `StatsOverview.resolveServerData`
|
|
42
|
-
* emits and the renderer consumes. Optional keys are omitted when the
|
|
43
|
-
* fluent setter wasn't called (smaller wire, simpler renderer
|
|
44
|
-
* branching).
|
|
45
|
-
*/
|
|
46
|
-
export interface StatMeta {
|
|
47
|
-
label: string
|
|
48
|
-
value?: string | number | null
|
|
49
|
-
description?: string
|
|
50
|
-
descriptionIcon?: StatDescriptionIcon
|
|
51
|
-
icon?: string
|
|
52
|
-
color?: StatColor
|
|
53
|
-
chart?: number[]
|
|
54
|
-
url?: string
|
|
55
|
-
openInNewTab?: boolean
|
|
56
|
-
extraAttributes?: Record<string, unknown>
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export class Stat {
|
|
60
|
-
protected _value?: string | number | null
|
|
61
|
-
protected _description?: string
|
|
62
|
-
protected _descriptionIcon?: StatDescriptionIcon
|
|
63
|
-
protected _icon?: string
|
|
64
|
-
protected _color?: StatColor
|
|
65
|
-
protected _chart?: number[]
|
|
66
|
-
protected _url?: string
|
|
67
|
-
protected _openInNewTab?: boolean
|
|
68
|
-
protected _extraAttributes?: Record<string, unknown>
|
|
69
|
-
|
|
70
|
-
protected constructor(protected _label: string) {}
|
|
71
|
-
|
|
72
|
-
/** Factory. The single positional arg is the stat's *label*
|
|
73
|
-
* (e.g. 'Users') — the value is set fluently via `.value(...)`. */
|
|
74
|
-
static make(label: string): Stat {
|
|
75
|
-
return new Stat(label)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Main number / string. `null` and `undefined` round-trip as `null`
|
|
79
|
-
* so the renderer can show a placeholder ("—") for "not yet
|
|
80
|
-
* computed" / "not applicable" without an extra sentinel. */
|
|
81
|
-
value(v: string | number | null | undefined): this {
|
|
82
|
-
this._value = v ?? null
|
|
83
|
-
return this
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Supplementary line below the value (e.g. '+12% this month'). */
|
|
87
|
-
description(t: string): this {
|
|
88
|
-
this._description = t
|
|
89
|
-
return this
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/** Tiny icon glued to the description. Position defaults to `'after'`
|
|
93
|
-
* (matches Filament v5's `IconPosition::After`). */
|
|
94
|
-
descriptionIcon(name: string, position: StatDescriptionIconPosition = 'after'): this {
|
|
95
|
-
this._descriptionIcon = { name, position }
|
|
96
|
-
return this
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** Main icon shown in the card chrome. String key into the panel's
|
|
100
|
-
* icon registry — same lookup as `Resource.icon`. */
|
|
101
|
-
icon(name: string): this {
|
|
102
|
-
this._icon = name
|
|
103
|
-
return this
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Color tint for the value + icon. */
|
|
107
|
-
color(c: StatColor): this {
|
|
108
|
-
this._color = c
|
|
109
|
-
return this
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** Inline-SVG sparkline data. Array of raw numbers — the renderer
|
|
113
|
-
* draws a path scaled to the card. No chart-lib dep. */
|
|
114
|
-
chart(values: number[]): this {
|
|
115
|
-
this._chart = [...values]
|
|
116
|
-
return this
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Wrap the card in an `<a href>`. */
|
|
120
|
-
url(href: string): this {
|
|
121
|
-
this._url = href
|
|
122
|
-
return this
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** When `.url()` is set, open it in a new tab. */
|
|
126
|
-
openUrlInNewTab(value: boolean = true): this {
|
|
127
|
-
this._openInNewTab = value
|
|
128
|
-
return this
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Extra HTML attributes spread onto the card root. JSON-clean only —
|
|
132
|
-
* values must serialize. */
|
|
133
|
-
extraAttributes(attrs: Record<string, unknown>): this {
|
|
134
|
-
this._extraAttributes = { ...attrs }
|
|
135
|
-
return this
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Serialize to the wire shape. Stats are ferried through
|
|
139
|
-
* `_widgetData` so this is a plain JSON object — no children, no
|
|
140
|
-
* `type` discriminator (the parent `StatsOverview` carries that). */
|
|
141
|
-
toMeta(): StatMeta {
|
|
142
|
-
const out: StatMeta = { label: this._label }
|
|
143
|
-
if (this._value !== undefined) out.value = this._value
|
|
144
|
-
if (this._description !== undefined) out.description = this._description
|
|
145
|
-
if (this._descriptionIcon !== undefined) out.descriptionIcon = this._descriptionIcon
|
|
146
|
-
if (this._icon !== undefined) out.icon = this._icon
|
|
147
|
-
if (this._color !== undefined) out.color = this._color
|
|
148
|
-
if (this._chart !== undefined) out.chart = this._chart
|
|
149
|
-
if (this._url !== undefined) out.url = this._url
|
|
150
|
-
if (this._openInNewTab !== undefined) out.openInNewTab = this._openInNewTab
|
|
151
|
-
if (this._extraAttributes !== undefined) out.extraAttributes = this._extraAttributes
|
|
152
|
-
return out
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plan #15 Phase B — `StatsOverview` element tests.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it } from 'node:test'
|
|
6
|
-
import assert from 'node:assert/strict'
|
|
7
|
-
|
|
8
|
-
import { Stat } from './Stat.js'
|
|
9
|
-
import { StatsOverview } from './StatsOverview.js'
|
|
10
|
-
import { resolveSchema, type RenderContext } from './resolveSchema.js'
|
|
11
|
-
import { isServerDataElement } from './ServerDataElement.js'
|
|
12
|
-
|
|
13
|
-
describe('StatsOverview element', () => {
|
|
14
|
-
describe('factory + identity', () => {
|
|
15
|
-
it('StatsOverview.make() returns an instance', () => {
|
|
16
|
-
const w = StatsOverview.make('overview')
|
|
17
|
-
assert.ok(w instanceof StatsOverview)
|
|
18
|
-
assert.equal(w.getType(), 'stats')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
it('falls back to subclass class name when no id passed', () => {
|
|
22
|
-
class UsersStats extends StatsOverview {}
|
|
23
|
-
assert.equal(UsersStats.make().getId(), 'UsersStats')
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
it('explicit id wins over class name', () => {
|
|
27
|
-
class UsersStats extends StatsOverview {}
|
|
28
|
-
assert.equal(UsersStats.make('explicit').getId(), 'explicit')
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('is a ServerDataElement', () => {
|
|
32
|
-
assert.equal(isServerDataElement(StatsOverview.make('a')), true)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('lazy default = true (inherited)', () => {
|
|
36
|
-
assert.equal(StatsOverview.make('a').isLazy(), true)
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
describe('columns()', () => {
|
|
41
|
-
it('instance setter wins over static', () => {
|
|
42
|
-
class StaticCols extends StatsOverview {
|
|
43
|
-
static override columns = 2
|
|
44
|
-
}
|
|
45
|
-
const w = StaticCols.make().columns(4)
|
|
46
|
-
assert.equal(w.getColumns(), 4)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('static columns is the fallback', () => {
|
|
50
|
-
class StaticCols extends StatsOverview {
|
|
51
|
-
static override columns = 3
|
|
52
|
-
}
|
|
53
|
-
assert.equal(StaticCols.make().getColumns(), 3)
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
it('returns undefined when neither set', () => {
|
|
57
|
-
assert.equal(StatsOverview.make('a').getColumns(), undefined)
|
|
58
|
-
})
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
describe('toMeta()', () => {
|
|
62
|
-
it('emits type=stats', async () => {
|
|
63
|
-
const [meta] = await resolveSchema([StatsOverview.make('a')])
|
|
64
|
-
assert.equal(meta!.type, 'stats')
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
it('omits columns when neither static nor instance set', async () => {
|
|
68
|
-
const [meta] = await resolveSchema([StatsOverview.make('a')])
|
|
69
|
-
assert.equal(meta!['columns'], undefined)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('emits columns when set on the instance', async () => {
|
|
73
|
-
const [meta] = await resolveSchema([StatsOverview.make('a').columns(4)])
|
|
74
|
-
assert.equal(meta!['columns'], 4)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('emits columns when set as a static on the subclass', async () => {
|
|
78
|
-
class S extends StatsOverview {
|
|
79
|
-
static override columns = 2
|
|
80
|
-
}
|
|
81
|
-
const [meta] = await resolveSchema([S.make()])
|
|
82
|
-
assert.equal(meta!['columns'], 2)
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('serverData wire-shape stamps land on top', async () => {
|
|
86
|
-
class S extends StatsOverview {}
|
|
87
|
-
const w = S.make().poll(60).lazy(false)
|
|
88
|
-
const [meta] = await resolveSchema([w])
|
|
89
|
-
assert.equal(meta!['serverData'], true)
|
|
90
|
-
assert.equal(meta!['id'], 'S')
|
|
91
|
-
assert.equal(meta!['poll'], 60)
|
|
92
|
-
assert.equal(meta!['lazy'], false)
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
describe('resolveServerData()', () => {
|
|
97
|
-
it('runs the static getStats() hook and serializes Stat[] into StatMeta[]', async () => {
|
|
98
|
-
class UsersStats extends StatsOverview {
|
|
99
|
-
static override async getStats() {
|
|
100
|
-
return [
|
|
101
|
-
Stat.make('Users').value(42).color('success'),
|
|
102
|
-
Stat.make('Sessions').value(7),
|
|
103
|
-
]
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
const data = await UsersStats.make().resolveServerData({} as RenderContext)
|
|
107
|
-
assert.deepEqual(data, {
|
|
108
|
-
stats: [
|
|
109
|
-
{ label: 'Users', value: 42, color: 'success' },
|
|
110
|
-
{ label: 'Sessions', value: 7 },
|
|
111
|
-
],
|
|
112
|
-
})
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('passes the render context to getStats', async () => {
|
|
116
|
-
let received: unknown = null
|
|
117
|
-
class CtxStats extends StatsOverview {
|
|
118
|
-
static override async getStats(ctx: RenderContext) {
|
|
119
|
-
received = ctx
|
|
120
|
-
return []
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
await CtxStats.make().resolveServerData({ user: { id: 1 } } as RenderContext)
|
|
124
|
-
assert.deepEqual(received, { user: { id: 1 } })
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('fluent .getStatsHandler(fn) overrides the static', async () => {
|
|
128
|
-
class StaticStats extends StatsOverview {
|
|
129
|
-
static override async getStats() { return [Stat.make('Static').value(1)] }
|
|
130
|
-
}
|
|
131
|
-
const w = StaticStats.make().getStatsHandler(async () => [Stat.make('Instance').value(2)])
|
|
132
|
-
const data = await w.resolveServerData({} as RenderContext)
|
|
133
|
-
assert.deepEqual(data, { stats: [{ label: 'Instance', value: 2 }] })
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('returns { stats: [] } when no hook is configured', async () => {
|
|
137
|
-
const data = await StatsOverview.make('empty').resolveServerData({} as RenderContext)
|
|
138
|
-
assert.deepEqual(data, { stats: [] })
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
})
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { ServerDataElement } from './ServerDataElement.js'
|
|
2
|
-
import type { RenderContext } from './resolveSchema.js'
|
|
3
|
-
import { Stat, type StatMeta } from './Stat.js'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Plan #15 Phase B — `StatsOverview` is the KPI-card row widget.
|
|
7
|
-
* Subclasses return an array of `Stat`s from `getStats(ctx)`; the
|
|
8
|
-
* resolver lays them out as a grid of cards.
|
|
9
|
-
*
|
|
10
|
-
* Subclass form (primary):
|
|
11
|
-
*
|
|
12
|
-
* import { StatsOverview, Stat } from '@pilotiq/pilotiq'
|
|
13
|
-
*
|
|
14
|
-
* export class UsersStats extends StatsOverview {
|
|
15
|
-
* static override columns = 3
|
|
16
|
-
* static override async getStats(ctx) {
|
|
17
|
-
* return [
|
|
18
|
-
* Stat.make('Users').value(await User.query().count()).color('success'),
|
|
19
|
-
* Stat.make('Active sessions').value(await Session.query().active().count()),
|
|
20
|
-
* Stat.make('Revenue (MTD)').value('$' + total).icon('dollar-sign'),
|
|
21
|
-
* ]
|
|
22
|
-
* }
|
|
23
|
-
* }
|
|
24
|
-
*
|
|
25
|
-
* // Page.schema()
|
|
26
|
-
* UsersStats.make()
|
|
27
|
-
*
|
|
28
|
-
* Fluent form (one-off — no subclass):
|
|
29
|
-
*
|
|
30
|
-
* StatsOverview.make('quick-kpis')
|
|
31
|
-
* .columns(2)
|
|
32
|
-
* .getStatsHandler(async () => [Stat.make('Foo').value(1)])
|
|
33
|
-
*
|
|
34
|
-
* Wire-shape:
|
|
35
|
-
* meta: { type: 'stats', columns?, serverData, id, lazy[, poll] }
|
|
36
|
-
* _widgetData[id]: { stats: StatMeta[] }
|
|
37
|
-
*
|
|
38
|
-
* Lazy default = true (inherited from `ServerDataElement`).
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
export type StatsHandler = (ctx: RenderContext) => Stat[] | Promise<Stat[]>
|
|
42
|
-
|
|
43
|
-
export interface StatsOverviewPayload {
|
|
44
|
-
stats: StatMeta[]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export class StatsOverview extends ServerDataElement {
|
|
48
|
-
/** Subclass-time defaults — read by `make()`-built instances unless
|
|
49
|
-
* the fluent setter overrides. Mirrors the `View.componentName /
|
|
50
|
-
* getData` precedent. */
|
|
51
|
-
static columns?: number
|
|
52
|
-
static getStats?: StatsHandler
|
|
53
|
-
|
|
54
|
-
// ─── Instance state (fluent overrides) ─────────────────────
|
|
55
|
-
private _columns?: number
|
|
56
|
-
private _getStats?: StatsHandler
|
|
57
|
-
|
|
58
|
-
// Public for subclass `new this(id)` (matches `View`).
|
|
59
|
-
constructor(id?: string) {
|
|
60
|
-
super()
|
|
61
|
-
if (id) this._id = id
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
static make(this: new (id?: string) => StatsOverview, id?: string): StatsOverview {
|
|
65
|
-
return new this(id)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Cards-per-row. Falls back to the static `columns` if the fluent
|
|
69
|
-
* setter wasn't called; renderer defaults further to a sensible
|
|
70
|
-
* number when neither is set. */
|
|
71
|
-
columns(n: number): this {
|
|
72
|
-
this._columns = n
|
|
73
|
-
return this
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/** Override the data hook. Useful for the fluent (no-subclass) form;
|
|
77
|
-
* for the subclass form prefer `static override async getStats(...)`. */
|
|
78
|
-
getStatsHandler(fn: StatsHandler): this {
|
|
79
|
-
this._getStats = fn
|
|
80
|
-
return this
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
getType(): string { return 'stats' }
|
|
84
|
-
|
|
85
|
-
/** Effective columns count. Instance setter wins; static is the
|
|
86
|
-
* fallback. Returns `undefined` when neither is set. */
|
|
87
|
-
getColumns(): number | undefined {
|
|
88
|
-
if (this._columns !== undefined) return this._columns
|
|
89
|
-
const ctor = this.constructor as { columns?: number }
|
|
90
|
-
return ctor.columns
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
toMeta(): Record<string, unknown> {
|
|
94
|
-
const meta: Record<string, unknown> = { type: 'stats' as const }
|
|
95
|
-
const cols = this.getColumns()
|
|
96
|
-
if (cols !== undefined) meta['columns'] = cols
|
|
97
|
-
return meta
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Run the configured stats hook. Falls back through:
|
|
102
|
-
* 1. instance setter (`overview.getStatsHandler(fn)`),
|
|
103
|
-
* 2. static method on the subclass (`static async getStats(ctx) {…}`),
|
|
104
|
-
* 3. empty list (`{ stats: [] }`).
|
|
105
|
-
*
|
|
106
|
-
* Resolved Stat objects are serialized to JSON-clean `StatMeta`s here
|
|
107
|
-
* so the renderer doesn't need to know about the `Stat` class.
|
|
108
|
-
*/
|
|
109
|
-
async resolveServerData(ctx: RenderContext): Promise<StatsOverviewPayload> {
|
|
110
|
-
let stats: Stat[] = []
|
|
111
|
-
if (this._getStats) {
|
|
112
|
-
stats = await this._getStats(ctx)
|
|
113
|
-
} else {
|
|
114
|
-
const ctor = this.constructor as { getStats?: StatsHandler }
|
|
115
|
-
if (ctor.getStats) stats = await ctor.getStats(ctx)
|
|
116
|
-
}
|
|
117
|
-
return { stats: stats.map(s => s.toMeta()) }
|
|
118
|
-
}
|
|
119
|
-
}
|
package/src/schema/StyleTag.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Element } from './Element.js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Head-safe element — emits an inline `<style>` block inside the panel's
|
|
5
|
-
* `<head>`. Use for CSS-variable overrides, conditional theming, or
|
|
6
|
-
* per-tenant brand colors that need to ship with the SSR document so
|
|
7
|
-
* there's no FOUC.
|
|
8
|
-
*
|
|
9
|
-
* For external stylesheets reach for `LinkTag.make({ rel: 'stylesheet',
|
|
10
|
-
* href: '...' })` instead.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* Pilotiq.renderHook('panels::styles', ({ user }) => [
|
|
14
|
-
* StyleTag.make(`
|
|
15
|
-
* :root { --pilotiq-brand: ${tenantBrand(user)} }
|
|
16
|
-
* `),
|
|
17
|
-
* ])
|
|
18
|
-
*/
|
|
19
|
-
export class StyleTag extends Element {
|
|
20
|
-
private constructor(private css: string, private nonce?: string) { super() }
|
|
21
|
-
|
|
22
|
-
static make(css: string, opts?: { nonce?: string }): StyleTag {
|
|
23
|
-
return new StyleTag(css, opts?.nonce)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
getType(): string { return 'style' }
|
|
27
|
-
|
|
28
|
-
toMeta() {
|
|
29
|
-
return {
|
|
30
|
-
type: 'style' as const,
|
|
31
|
-
css: this.css,
|
|
32
|
-
...(this.nonce ? { nonce: this.nonce } : {}),
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|