@antelopejs/dms 0.9.8 → 0.10.0
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 +102 -0
- package/README.md +1 -1
- package/data/module-store/catalog.json +2 -2
- package/dist/attachments/table-view.js +2 -2
- package/dist/attachments/table-view.js.map +1 -1
- package/dist/automation/actions.d.ts +2 -0
- package/dist/automation/actions.js +116 -71
- package/dist/automation/actions.js.map +1 -1
- package/dist/automation/i18n.d.ts +4 -0
- package/dist/automation/i18n.js +19 -0
- package/dist/automation/i18n.js.map +1 -0
- package/dist/automation/send-notification.d.ts +21 -0
- package/dist/automation/send-notification.js +163 -0
- package/dist/automation/send-notification.js.map +1 -0
- package/dist/automation/triggers.js +19 -25
- package/dist/automation/triggers.js.map +1 -1
- package/dist/client-origin-cors.d.ts +1 -0
- package/dist/client-origin-cors.js +19 -0
- package/dist/client-origin-cors.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +5 -3
- package/dist/config.js.map +1 -1
- package/dist/frontend-module.d.ts +4 -0
- package/dist/frontend-module.js +37 -0
- package/dist/frontend-module.js.map +1 -0
- package/dist/implementations/dms/client-ip.js +1 -1
- package/dist/implementations/dms/client-ip.js.map +1 -1
- package/dist/implementations/dms/dev-reload.d.ts +5 -0
- package/dist/implementations/dms/dev-reload.js +23 -3
- package/dist/implementations/dms/dev-reload.js.map +1 -1
- package/dist/implementations/dms/frontend-modules.d.ts +2 -4
- package/dist/implementations/dms/frontend-modules.js +22 -89
- package/dist/implementations/dms/frontend-modules.js.map +1 -1
- package/dist/implementations/dms/frontend-ready.d.ts +12 -2
- package/dist/implementations/dms/frontend-ready.js +34 -4
- package/dist/implementations/dms/frontend-ready.js.map +1 -1
- package/dist/implementations/dms/layout-banners.d.ts +2 -1
- package/dist/implementations/dms/layout-banners.js +9 -0
- package/dist/implementations/dms/layout-banners.js.map +1 -1
- package/dist/implementations/dms/manifest.d.ts +1 -2
- package/dist/implementations/dms/manifest.js +2 -0
- package/dist/implementations/dms/manifest.js.map +1 -1
- package/dist/implementations/dms/page.d.ts +4 -3
- package/dist/implementations/dms/page.js +49 -18
- package/dist/implementations/dms/page.js.map +1 -1
- package/dist/implementations/dms/permissions-resolver.d.ts +2 -2
- package/dist/implementations/dms/permissions-resolver.js +2 -2
- package/dist/implementations/dms/permissions-resolver.js.map +1 -1
- package/dist/implementations/dms/realtime.js +1 -0
- package/dist/implementations/dms/realtime.js.map +1 -1
- package/dist/implementations/dms-base/bulk-selection.d.ts +1 -1
- package/dist/implementations/dms-base/bulk-selection.js +23 -1
- package/dist/implementations/dms-base/bulk-selection.js.map +1 -1
- package/dist/implementations/dms-base/filter-tokens.js +5 -3
- package/dist/implementations/dms-base/filter-tokens.js.map +1 -1
- package/dist/implementations/dms-base/search-route.d.ts +1 -0
- package/dist/implementations/dms-base/search-route.js +35 -13
- package/dist/implementations/dms-base/search-route.js.map +1 -1
- package/dist/implementations/dms-base/table-view.js +11 -6
- package/dist/implementations/dms-base/table-view.js.map +1 -1
- package/dist/implementations/dms-notifications/index.d.ts +2 -2
- package/dist/implementations/dms-notifications/index.js +5 -5
- package/dist/implementations/dms-notifications/index.js.map +1 -1
- package/dist/index.js +28 -48
- package/dist/index.js.map +1 -1
- package/dist/pages/modules/index.d.ts +1 -0
- package/dist/pages/modules/index.js +1 -0
- package/dist/pages/modules/index.js.map +1 -1
- package/dist/pages/modules/modules-store.d.ts +9 -0
- package/dist/pages/modules/modules-store.js +30 -0
- package/dist/pages/modules/modules-store.js.map +1 -0
- package/dist/pages/settings/users/account-credentials.js +2 -2
- package/dist/pages/settings/users/account-credentials.js.map +1 -1
- package/dist/pages/settings/users/account-data-store.js +25 -8
- package/dist/pages/settings/users/account-data-store.js.map +1 -1
- package/dist/pages/settings/users/invite-extension-routes.js +9 -3
- package/dist/pages/settings/users/invite-extension-routes.js.map +1 -1
- package/dist/pages/settings/users/member-management.js +13 -14
- package/dist/pages/settings/users/member-management.js.map +1 -1
- package/dist/pages/settings/users/profile.d.ts +1 -4
- package/dist/pages/settings/users/profile.js +0 -35
- package/dist/pages/settings/users/profile.js.map +1 -1
- package/dist/pages/settings/users/role-editor-store.js +26 -18
- package/dist/pages/settings/users/role-editor-store.js.map +1 -1
- package/dist/pages/settings/users/role-editor.d.ts +0 -1
- package/dist/pages/settings/users/role-editor.js +1 -2
- package/dist/pages/settings/users/role-editor.js.map +1 -1
- package/dist/pages/settings/users/role-preview.js +1 -2
- package/dist/pages/settings/users/role-preview.js.map +1 -1
- package/dist/pages/settings/users/roles.js +2 -2
- package/dist/pages/settings/users/roles.js.map +1 -1
- package/dist/pages/settings/users/two-factor-operations.js.map +1 -1
- package/dist/realtime/broker.d.ts +6 -0
- package/dist/realtime/broker.js +8 -1
- package/dist/realtime/broker.js.map +1 -1
- package/dist/realtime/presence.d.ts +8 -3
- package/dist/realtime/presence.js +8 -4
- package/dist/realtime/presence.js.map +1 -1
- package/dist/realtime/sessions.d.ts +11 -1
- package/dist/realtime/sessions.js +21 -3
- package/dist/realtime/sessions.js.map +1 -1
- package/dist/realtime/table-view.d.ts +2 -2
- package/dist/realtime/table-view.js +4 -3
- package/dist/realtime/table-view.js.map +1 -1
- package/dist/routes/auth/client-ip.d.ts +1 -0
- package/dist/routes/auth/client-ip.js +18 -0
- package/dist/routes/auth/client-ip.js.map +1 -1
- package/dist/routes/auth/oauth/config.d.ts +2 -1
- package/dist/routes/auth/oauth/config.js +5 -1
- package/dist/routes/auth/oauth/config.js.map +1 -1
- package/dist/routes/auth/session-handoff.d.ts +0 -1
- package/dist/routes/auth/session-handoff.js +0 -2
- package/dist/routes/auth/session-handoff.js.map +1 -1
- package/dist/routes/auth.js +3 -2
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/index.d.ts +0 -1
- package/dist/routes/index.js +0 -1
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/realtime.d.ts +13 -1
- package/dist/routes/realtime.js +114 -29
- package/dist/routes/realtime.js.map +1 -1
- package/dist/startup-config.d.ts +2 -0
- package/dist/startup-config.js +62 -0
- package/dist/startup-config.js.map +1 -0
- package/dist/store/interfaces.d.ts +3 -2
- package/dist/store/interfaces.js +16 -6
- package/dist/store/interfaces.js.map +1 -1
- package/dist/store/listing.js +24 -13
- package/dist/store/listing.js.map +1 -1
- package/dist/store/operations.js +4 -0
- package/dist/store/operations.js.map +1 -1
- package/dist/store/requirements.js +3 -2
- package/dist/store/requirements.js.map +1 -1
- package/dist/store/runtime.d.ts +10 -1
- package/dist/store/runtime.js +33 -6
- package/dist/store/runtime.js.map +1 -1
- package/dist/store/types.d.ts +10 -0
- package/dist/validation/auth.schema.d.ts +2 -2
- package/dist/validation/member-invite.schema.d.ts +2 -10
- package/dist/validation/member-invite.schema.js +2 -15
- package/dist/validation/member-invite.schema.js.map +1 -1
- package/frontend-vue/dms.frontend.ts +24 -5
- package/frontend-vue/dms.server.ts +17 -0
- package/frontend-vue/layers/dms-auth/server/accounts.ts +3 -4
- package/frontend-vue/layers/dms-core/app/build/composables/renderNow.ts +34 -0
- package/frontend-vue/layers/dms-core/app/build/composables/user/tablePreferences.ts +5 -1
- package/frontend-vue/layers/dms-core/app/build/utils/crossTab.ts +199 -0
- package/frontend-vue/layers/dms-core/app/build/utils/sharedRealtimeConnection.ts +410 -0
- package/frontend-vue/layers/dms-core/app/composables/auth/useApiData.ts +77 -12
- package/frontend-vue/layers/dms-core/app/composables/data-types/useDataType.ts +26 -0
- package/frontend-vue/layers/dms-core/app/composables/hydration/isHydratingComponent.ts +29 -0
- package/frontend-vue/layers/dms-core/app/composables/live/livePauseSource.ts +29 -0
- package/frontend-vue/layers/dms-core/app/composables/period/compareResolvers.ts +150 -9
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriod.ts +6 -4
- package/frontend-vue/layers/dms-core/app/composables/period/usePeriodScope.ts +27 -1
- package/frontend-vue/layers/dms-core/app/composables/realtime/useUserRealtime.ts +256 -119
- package/frontend-vue/layers/dms-core/app/composables/translation/useComposedText.ts +21 -8
- package/frontend-vue/layers/dms-core/app/composables/translation/useTranslation.ts +22 -5
- package/frontend-vue/layers/dms-core/app/plugins/dev-error-log.ts +16 -0
- package/frontend-vue/layers/dms-core/app/types/user.ts +6 -0
- package/frontend-vue/layers/dms-core/app/utils/composedText.ts +7 -2
- package/frontend-vue/layers/dms-core/app/utils/formatter.ts +166 -35
- package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +18 -1
- package/frontend-vue/layers/dms-core/i18n/locales/core-en-GB.json +134 -2
- package/frontend-vue/layers/dms-core/i18n/locales/core-fr-FR.json +134 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardBanners.vue +3 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +41 -21
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardPageBody.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardSidebar.vue +4 -19
- package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +11 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/GithubStarPrompt.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionBar.vue +8 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue +14 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/RowSidePanel.vue +43 -82
- package/frontend-vue/layers/dms-layout/app/build/components/layout/SidebarUserMenu.vue +44 -3
- package/frontend-vue/layers/dms-layout/app/build/components/layout/UserIdentity.vue +11 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleCatalogTile.vue +132 -35
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleManageMenu.vue +59 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleSourceLabel.vue +25 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreBanners.vue +73 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreOperation.vue +116 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreRequirements.vue +8 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleStoreTile.vue +85 -207
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTile.vue +10 -3
- package/frontend-vue/layers/dms-layout/app/build/components/pages/modules/ModuleTileSkeleton.vue +68 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxDisplay.vue +24 -8
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/notification/NotificationInboxItem.vue +8 -5
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/region/RegionTimeZoneInput.vue +1 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/role-permissions.ts +19 -0
- package/frontend-vue/layers/dms-layout/app/build/components/pages/settings/roles/useRoleEditor.ts +2 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useSidePanelWidth.ts +31 -70
- package/frontend-vue/layers/dms-layout/app/build/composables/notification/useNotificationGroupsOpen.ts +11 -1
- package/frontend-vue/layers/dms-layout/app/build/utils/dev-reload-stream.ts +81 -0
- package/frontend-vue/layers/dms-layout/app/build/utils/module-store-catalog.ts +232 -36
- package/frontend-vue/layers/dms-layout/app/build/utils/modules-catalog.ts +122 -14
- package/frontend-vue/layers/dms-layout/app/composables/layout/useLayoutBanners.ts +32 -3
- package/frontend-vue/layers/dms-layout/app/composables/layout/usePageRecord.ts +50 -0
- package/frontend-vue/layers/dms-layout/app/composables/layout/useServedHeaderActions.ts +25 -7
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleHistory.ts +3 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStore.ts +51 -4
- package/frontend-vue/layers/dms-layout/app/composables/page/useModuleStoreActions.ts +194 -0
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageComponentPreload.ts +23 -3
- package/frontend-vue/layers/dms-layout/app/composables/page/usePageLayout.ts +4 -2
- package/frontend-vue/layers/dms-layout/app/composables/page/useSiteLayout.ts +6 -1
- package/frontend-vue/layers/dms-layout/app/custom-layouts/DefaultLayout.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/custom-layouts/SettingsLayout.vue +9 -0
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules-store.vue +291 -0
- package/frontend-vue/layers/dms-layout/app/custom-pages/modules.vue +87 -474
- package/frontend-vue/layers/dms-layout/app/middleware/module-routing.global.ts +3 -0
- package/frontend-vue/layers/dms-layout/app/pages/[...slug].vue +6 -22
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-navigation.client.ts +2 -1
- package/frontend-vue/layers/dms-layout/app/plugins/command-palette-personal-pages.client.ts +14 -44
- package/frontend-vue/layers/dms-layout/app/plugins/dms-dev-reload.client.ts +14 -9
- package/frontend-vue/layers/dms-layout/app/theme/form-controls.ts +9 -4
- package/frontend-vue/layers/dms-layout/app/theme/surfaces.ts +22 -6
- package/frontend-vue/layers/dms-layout/app/types/module-store.ts +9 -0
- package/frontend-vue/layers/dms-layout/app/types/page.ts +15 -1
- package/frontend-vue/layers/dms-layout/app/utils/account-menu.ts +11 -0
- package/frontend-vue/layers/dms-layout/app/utils/breadcrumb.ts +57 -0
- package/frontend-vue/layers/dms-layout/app/utils/pageQuery.ts +26 -0
- package/frontend-vue/layers/dms-layout/app/utils/pageRecord.ts +71 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +39 -14
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +38 -13
- package/frontend-vue/layers/dms-ui/app/build/components/containers/TargetComponentTree.vue +31 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/constants.ts +25 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/drawer/DynamicDrawer.vue +244 -15
- package/frontend-vue/layers/dms-ui/app/build/components/containers/modal/DynamicModal.vue +42 -25
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowHeader.vue +153 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/RowNotFound.vue +44 -0
- package/frontend-vue/layers/dms-ui/app/build/components/containers/row/drawerRowHeader.ts +35 -0
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormEntries.vue +44 -9
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormErrorSummary.vue +11 -4
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +38 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldNotes.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSectionNav.vue +3 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormSections.vue +106 -27
- package/frontend-vue/layers/dms-ui/app/build/components/table/Actions.vue +12 -4
- package/frontend-vue/layers/dms-ui/app/build/components/table/Empty.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table/FiltersRow.vue +38 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Pagination.vue +55 -54
- package/frontend-vue/layers/dms-ui/app/build/components/table/RowSelection.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Table.vue +396 -288
- package/frontend-vue/layers/dms-ui/app/build/components/table/Tabs.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table/Views.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardAvatar.vue +59 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardGridSkeleton.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardRowActions.vue +38 -0
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/CardsDisplay.vue +148 -104
- package/frontend-vue/layers/dms-ui/app/build/components/table-view/LiveHoldBanner.vue +17 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/bulkSelection.ts +43 -9
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowComponentOptions.ts +76 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/rowNavigation.ts +172 -27
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +270 -46
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/closingLayers.ts +186 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/context.ts +14 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/drawerSize.ts +229 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/containers/useResizableSize.ts +175 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/metricCells.ts +18 -35
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/numberSuffix.ts +47 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +99 -24
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerFieldTypes.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationFilter.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationRows.ts +71 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/relationValue.ts +39 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/twoLineCell.ts +3 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/useColumnValueRenderer.ts +6 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/form/createFormFields.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldSaved.ts +40 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/fieldValueRule.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryContext.ts +5 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +42 -7
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formLayout.ts +106 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formSections.ts +32 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/readonlyValue.ts +19 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/registerFormFunctions.ts +27 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/repeaterTable.ts +65 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/serverFieldErrors.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/toasterClearance.ts +118 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/useInstantForm.ts +12 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/currentPageLive.ts +41 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/livePoller.ts +10 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/live/pageReadClock.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/live/shortcuts.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/live/usePageLiveHost.ts +17 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/live/useUpdatedLabel.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/pageToolbarContext.ts +75 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/page-toolbar/toolbarControlHeight.ts +29 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodComparison.ts +52 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodDisplay.ts +21 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/periodShortLabels.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/period/usePeriodDraft.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRelationFilterLabels.ts +73 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useRowScrollAnchor.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTable.ts +9 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/useTableColumns.ts +1 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/archivedCount.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/filterEditorValue.ts +38 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/formatFilterValue.ts +33 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table/utils/scrollEdges.ts +31 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useCardFields.ts +33 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useMobileDisplay.ts +48 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useScrolledPastTop.ts +41 -18
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableFooter.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLinkedVisit.ts +78 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableLiveHold.ts +135 -22
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +56 -25
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +77 -32
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViews.ts +86 -10
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/bulkActions.ts +14 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/card.ts +127 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/compareValues.ts +13 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/expandedRows.ts +28 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/groupedRows.ts +114 -1
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/linkedArrival.ts +308 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/locateRow.ts +106 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pageArrival.ts +34 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/pinnedRows.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/quickFilters.ts +41 -33
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/recordLink.ts +24 -8
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableCounts.ts +113 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/tableQuery.ts +27 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/utils/views.ts +22 -6
- package/frontend-vue/layers/dms-ui/app/build/utils/addressSuggestions.ts +49 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/eyebrow.ts +12 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/fieldOptionsI18n.ts +51 -11
- package/frontend-vue/layers/dms-ui/app/build/utils/inputWidth.ts +53 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/numberAdjustment.ts +6 -3
- package/frontend-vue/layers/dms-ui/app/build/utils/relativeDate.ts +19 -5
- package/frontend-vue/layers/dms-ui/app/build/utils/scrollWithin.ts +99 -0
- package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +36 -14
- package/frontend-vue/layers/dms-ui/app/components/PasswordStrength.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/RecursiveComponent.vue +9 -1
- package/frontend-vue/layers/dms-ui/app/components/blocks/LiveToggleBlock.vue +80 -32
- package/frontend-vue/layers/dms-ui/app/components/blocks/PageToolbarBlock.vue +137 -0
- package/frontend-vue/layers/dms-ui/app/components/blocks/StatGroupBlock.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +16 -2
- package/frontend-vue/layers/dms-ui/app/components/chart/Chart.vue +24 -5
- package/frontend-vue/layers/dms-ui/app/components/chart/ChartCard.vue +41 -23
- package/frontend-vue/layers/dms-ui/app/components/confirm/ConfirmModal.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/container-footer/ContainerFooter.vue +34 -0
- package/frontend-vue/layers/dms-ui/app/components/field-row/FieldRow.vue +25 -2
- package/frontend-vue/layers/dms-ui/app/components/flow-canvas/FlowCanvas.vue +2 -2
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +118 -36
- package/frontend-vue/layers/dms-ui/app/components/form/components/DatePicker.vue +20 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Display.vue +13 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Image.vue +8 -3
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +53 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +29 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputNumber.vue +45 -8
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputPercentage.vue +28 -5
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +5 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputText.vue +19 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputTime.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +205 -65
- package/frontend-vue/layers/dms-ui/app/components/form/components/Repeater.vue +80 -30
- package/frontend-vue/layers/dms-ui/app/components/form/components/RepeaterTable.vue +203 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/Select.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +11 -2
- package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +79 -70
- package/frontend-vue/layers/dms-ui/app/components/kpi/KpiCard.vue +117 -21
- package/frontend-vue/layers/dms-ui/app/components/meter/Meter.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/period/PeriodSelector.vue +113 -34
- package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +14 -2
- package/frontend-vue/layers/dms-ui/app/components/section-header/Eyebrow.vue +6 -1
- package/frontend-vue/layers/dms-ui/app/components/segmented/Segmented.vue +13 -0
- package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +52 -3
- package/frontend-vue/layers/dms-ui/app/components/tab/Tab.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanBoard.vue +45 -35
- package/frontend-vue/layers/dms-ui/app/components/table-view/KanbanDisplay.vue +4 -1
- package/frontend-vue/layers/dms-ui/app/components/table-view/TableView.vue +410 -96
- package/frontend-vue/layers/dms-ui/app/components/top-list/TopListCard.vue +33 -5
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexCategoryLabels.ts +68 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexDatetimeBuckets.ts +306 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/formatValue.ts +4 -3
- package/frontend-vue/layers/dms-ui/app/composables/chart/heatmapColors.ts +93 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/localizeSeries.ts +62 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +116 -8
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.types.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/composables/containers/types.ts +84 -1
- package/frontend-vue/layers/dms-ui/app/composables/containers/useDrawer.ts +69 -8
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field-saved.ts +11 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/field.ts +4 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/types/functions.ts +1 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +142 -21
- package/frontend-vue/layers/dms-ui/app/composables/live/usePageLive.ts +11 -4
- package/frontend-vue/layers/dms-ui/app/composables/page-toolbar/usePageToolbarSize.ts +30 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/kanban.ts +4 -2
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +22 -3
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +4 -0
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/display.ts +24 -1
- package/frontend-vue/layers/dms-ui/app/plugins/closing-layers.client.ts +10 -0
- package/frontend-vue/layers/dms-ui/app/plugins/live-pause-source.ts +15 -0
- package/frontend-vue/layers/dms-ui/app/plugins/register.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/types/input-number.ts +3 -2
- package/frontend-vue/layers/dms-ui/app/types/page-toolbar.ts +7 -0
- package/frontend-vue/layers/dms-ui/app/types/row-action.ts +0 -2
- package/frontend-vue/layers/dms-ui/app/types/row-navigation.ts +17 -0
- package/frontend-vue/layers/dms-ui/app/types/table/query.ts +2 -1
- package/frontend-vue/layers/dms-ui/app/utils/blockRefresh.ts +3 -1
- package/frontend-vue/layers/dms-ui/app/utils/componentTree.ts +24 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +16 -4
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +16 -4
- package/frontend-vue/package.json +2 -2
- package/package.json +7 -6
- package/skills/dms/SKILL.md +1 -1
- package/skills/dms-auth/SKILL.md +5 -3
- package/skills/dms-best-practices/REFERENCE.md +2 -0
- package/skills/dms-best-practices/SKILL.md +4 -0
- package/skills/dms-module/SKILL.md +3 -2
- package/skills/dms-pages/REFERENCE.md +125 -16
- package/skills/dms-pages/SKILL.md +1 -1
- package/skills/dms-project/DEV-SERVERS.md +23 -1
- package/skills/dms-project/REFERENCE.md +1 -1
- package/skills/dms-project/SKILL.md +4 -1
- package/skills/dms-project/scripts/dms-dev.sh +205 -17
- package/dist/routes/startup-gate.d.ts +0 -7
- package/dist/routes/startup-gate.js +0 -39
- package/dist/routes/startup-gate.js.map +0 -1
- package/frontend-vue/layers/dms-core/app/composables/period/periodRenderNow.ts +0 -42
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
import { usePageRecordLabel } from "#dms-core/app/composables/page/usePageRecordLabel";
|
|
12
12
|
import type { CategoryInfo } from "../../../types/page";
|
|
13
13
|
import { resolveModuleLandingSlug } from "../../../utils/moduleLanding";
|
|
14
|
+
import {
|
|
15
|
+
foldBreadcrumb,
|
|
16
|
+
isFoldedCrumbs,
|
|
17
|
+
withParentCrumb,
|
|
18
|
+
} from "../../../utils/breadcrumb";
|
|
19
|
+
import { fillRouteParams } from "../../../utils/pageQuery";
|
|
14
20
|
|
|
15
21
|
const HOME_ICON = "i-ph-house-light";
|
|
16
22
|
/** Breadcrumb slot of the folded middle crumbs on small screens. */
|
|
@@ -130,6 +136,26 @@ function moduleLandingSlug(
|
|
|
130
136
|
);
|
|
131
137
|
}
|
|
132
138
|
|
|
139
|
+
/**
|
|
140
|
+
* The crumb of the page the current one is a detail of (`parentSlug`), its
|
|
141
|
+
* route parameters filled from the current page's: none when it is missing,
|
|
142
|
+
* out of reach, or names a parameter the current page lacks.
|
|
143
|
+
*/
|
|
144
|
+
const parentCrumb = computed((): BreadcrumbItem | null => {
|
|
145
|
+
const current = siteLayout.findMatchingRoute(route.path);
|
|
146
|
+
const parentSlug = current?.metadata.parentSlug;
|
|
147
|
+
if (!parentSlug) return null;
|
|
148
|
+
const path = fillRouteParams(parentSlug, current.params);
|
|
149
|
+
if (path.includes(":")) return null;
|
|
150
|
+
const parent = siteLayout.findMatchingRoute(path)?.metadata;
|
|
151
|
+
if (!parent || parent.hasAccess === false) return null;
|
|
152
|
+
const target = buildBreadcrumbTarget(path, parent, route.query);
|
|
153
|
+
return {
|
|
154
|
+
label: processI18n(parent.displayName),
|
|
155
|
+
...(target ? { to: target } : {}),
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
|
|
133
159
|
const breadcrumb = computed((): BreadcrumbItem[] => {
|
|
134
160
|
const base: BreadcrumbItem[] = [
|
|
135
161
|
{ icon: HOME_ICON, to: homepage || "/", "aria-label": t("header.home") },
|
|
@@ -143,7 +169,7 @@ const breadcrumb = computed((): BreadcrumbItem[] => {
|
|
|
143
169
|
|
|
144
170
|
const paths = route.path.split("/").filter((path) => path);
|
|
145
171
|
|
|
146
|
-
const
|
|
172
|
+
const pathCrumbs = base.concat(
|
|
147
173
|
paths
|
|
148
174
|
.map((path, index): BreadcrumbItem | null => {
|
|
149
175
|
const to = `/${paths.slice(0, index + 1).join("/")}`;
|
|
@@ -170,6 +196,7 @@ const breadcrumb = computed((): BreadcrumbItem[] => {
|
|
|
170
196
|
})
|
|
171
197
|
.filter((item) => item !== null),
|
|
172
198
|
);
|
|
199
|
+
const crumbs = withParentCrumb(pathCrumbs, parentCrumb.value);
|
|
173
200
|
|
|
174
201
|
// Written as the row has it: an email address keeps its lowercase.
|
|
175
202
|
const last = crumbs.at(-1);
|
|
@@ -183,32 +210,25 @@ const breadcrumb = computed((): BreadcrumbItem[] => {
|
|
|
183
210
|
return crumbs;
|
|
184
211
|
});
|
|
185
212
|
|
|
213
|
+
// The middle crumbs fold into a "…" menu (see the `#ellipsis` slot) so a
|
|
214
|
+
// deep page still fits a phone without losing the way back up.
|
|
186
215
|
const mobileBreadcrumb = computed(
|
|
187
|
-
(): (BreadcrumbItem & { children?: DropdownMenuItem[] })[] =>
|
|
188
|
-
|
|
189
|
-
return
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
breadcrumb.value[0]!,
|
|
196
|
-
{
|
|
197
|
-
slot: MOBILE_ELLIPSIS_SLOT,
|
|
198
|
-
children: breadcrumb.value.slice(1, -1).map((x) => ({
|
|
199
|
-
label: x.label,
|
|
200
|
-
to: x.to,
|
|
201
|
-
})),
|
|
202
|
-
},
|
|
203
|
-
breadcrumb.value.slice(-1)[0]!,
|
|
204
|
-
];
|
|
205
|
-
},
|
|
216
|
+
(): (BreadcrumbItem & { children?: DropdownMenuItem[] })[] =>
|
|
217
|
+
foldBreadcrumb(breadcrumb.value, MOBILE_ELLIPSIS_SLOT).map((crumb) => {
|
|
218
|
+
if (!isFoldedCrumbs(crumb)) return crumb;
|
|
219
|
+
return {
|
|
220
|
+
slot: crumb.slot,
|
|
221
|
+
children: crumb.children.map((x) => ({ label: x.label, to: x.to })),
|
|
222
|
+
};
|
|
223
|
+
}),
|
|
206
224
|
);
|
|
207
225
|
</script>
|
|
208
226
|
|
|
209
227
|
<template>
|
|
210
228
|
<div data-dms-persistent-header>
|
|
211
|
-
|
|
229
|
+
<!-- The phone toggle below is the only one: the navbar's own would sit
|
|
230
|
+
next to it. -->
|
|
231
|
+
<UDashboardNavbar :toggle="false">
|
|
212
232
|
<template #leading>
|
|
213
233
|
<UButton
|
|
214
234
|
class="lg:hidden"
|
|
@@ -5,6 +5,7 @@ import PageHeaderActionsOutlet from "./PageHeaderActionsOutlet.vue";
|
|
|
5
5
|
import PageSkeleton from "./PageSkeleton.vue";
|
|
6
6
|
import type { LayoutHeaderAction } from "./PageHeaderActionBar.vue";
|
|
7
7
|
import { providePageHeaderActions } from "../../../composables/layout/usePageHeaderActions";
|
|
8
|
+
import type { PageRecordSource } from "../../../composables/layout/usePageRecord";
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
hideHeader?: boolean;
|
|
@@ -18,6 +19,10 @@ interface Props {
|
|
|
18
19
|
* when one declares an `availability` (`headerActionsQuery`).
|
|
19
20
|
*/
|
|
20
21
|
headerActionsQuery?: Record<string, string>;
|
|
22
|
+
/** The route parameters (`:id`) they were resolved for, likewise. */
|
|
23
|
+
headerActionsParams?: Record<string, string>;
|
|
24
|
+
/** The record the page shows, which header buttons may act on (`record`). */
|
|
25
|
+
record?: PageRecordSource;
|
|
21
26
|
/** Space between the page header and the page. */
|
|
22
27
|
headerClass?: string;
|
|
23
28
|
}
|
|
@@ -29,6 +34,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
29
34
|
description: undefined,
|
|
30
35
|
headerActions: () => [],
|
|
31
36
|
headerActionsQuery: undefined,
|
|
37
|
+
headerActionsParams: undefined,
|
|
38
|
+
record: undefined,
|
|
32
39
|
headerClass: "pb-6",
|
|
33
40
|
});
|
|
34
41
|
|
|
@@ -67,6 +74,8 @@ const PAGE_SLOT_CLASS =
|
|
|
67
74
|
<PageHeaderActionsOutlet
|
|
68
75
|
:actions="props.headerActions"
|
|
69
76
|
:served-query="props.headerActionsQuery"
|
|
77
|
+
:served-params="props.headerActionsParams"
|
|
78
|
+
:record="props.record"
|
|
70
79
|
/>
|
|
71
80
|
</template>
|
|
72
81
|
</PageHeader>
|
|
@@ -14,13 +14,10 @@ import { useKeyboardPlatform } from "#dms-ui/app/composables/global/keyboardPlat
|
|
|
14
14
|
import { useMediaQuery } from "@vueuse/core";
|
|
15
15
|
import DmsSidebarUserMenu from "./SidebarUserMenu.vue";
|
|
16
16
|
|
|
17
|
-
const SETTINGS_PATH = "/settings";
|
|
18
17
|
const MODULES_PATH = "/modules";
|
|
19
|
-
// Registered
|
|
20
|
-
const SETTINGS_FULL_ID = "settings";
|
|
18
|
+
// Registered id of the Modules entry, so "Preview as role" can lock it.
|
|
21
19
|
const MODULES_FULL_ID = "modules";
|
|
22
20
|
const MODULES_TREE_KEY = "modules";
|
|
23
|
-
const SETTINGS_ICON = "i-ph-gear-six-light";
|
|
24
21
|
const MODULES_ICON = "i-ph-squares-four-light";
|
|
25
22
|
const BACK_ICON = "i-ph-arrow-left-light";
|
|
26
23
|
const ESCAPE_KEY = "Escape";
|
|
@@ -254,21 +251,9 @@ const footerItems = computed((): NavigationMenuItem[] => {
|
|
|
254
251
|
});
|
|
255
252
|
}
|
|
256
253
|
|
|
257
|
-
//
|
|
258
|
-
// destinations, regardless of the router's
|
|
259
|
-
|
|
260
|
-
addActiveStateToMenuItem(
|
|
261
|
-
{
|
|
262
|
-
fullId: SETTINGS_FULL_ID,
|
|
263
|
-
label: t("menu.section.settings"),
|
|
264
|
-
to: SETTINGS_PATH,
|
|
265
|
-
icon: SETTINGS_ICON,
|
|
266
|
-
} as DmsMenuItem,
|
|
267
|
-
currentFullId.value,
|
|
268
|
-
currentRoute.value,
|
|
269
|
-
),
|
|
270
|
-
);
|
|
271
|
-
|
|
254
|
+
// The settings are reached from the account menu, not from here. Back and
|
|
255
|
+
// Modules only highlight their destinations, regardless of the router's
|
|
256
|
+
// default prefix matching.
|
|
272
257
|
if (isOwner.value) {
|
|
273
258
|
result.push({
|
|
274
259
|
fullId: MODULES_FULL_ID,
|
|
@@ -14,6 +14,8 @@ const GITHUB_STARS_CACHE_KEY = "dms-github-stars";
|
|
|
14
14
|
const GITHUB_STARS_CACHE_TTL_MS = 60 * 60 * 1000;
|
|
15
15
|
|
|
16
16
|
const { locale, setLocale, t } = useI18n();
|
|
17
|
+
const { loggedIn: isLoggedIn } = useDmsUserSession();
|
|
18
|
+
const { changeLanguage } = useUserLanguage();
|
|
17
19
|
const { uniqueLocales } = useUniqueLocales();
|
|
18
20
|
const { links } = useFooterLinks();
|
|
19
21
|
const { processI18n } = useTranslation();
|
|
@@ -49,9 +51,7 @@ const githubStarsSettled = ref(false);
|
|
|
49
51
|
const formattedGithubStars = computed(() =>
|
|
50
52
|
githubStars.value === null
|
|
51
53
|
? ""
|
|
52
|
-
:
|
|
53
|
-
githubStars.value,
|
|
54
|
-
),
|
|
54
|
+
: formatNumber(githubStars.value, locale.value, { notation: "compact" }),
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
function readCachedStars(): CachedStars | null {
|
|
@@ -104,7 +104,15 @@ onMounted(async () => {
|
|
|
104
104
|
githubStarsSettled.value = true;
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
+
// A signed-in user on a page of this layout (the account switcher) switches
|
|
108
|
+
// their profile's language too: the session applies that one on every load,
|
|
109
|
+
// and the server writes in it, so switching the screen alone would leave the
|
|
110
|
+
// two apart. A visitor's choice lives in the locale cookie.
|
|
107
111
|
async function onLocaleChange(code: unknown) {
|
|
112
|
+
if (isLoggedIn.value) {
|
|
113
|
+
await changeLanguage(code as string);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
108
116
|
await setLocale(code as typeof locale.value);
|
|
109
117
|
}
|
|
110
118
|
</script>
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
+
import { useOpenDialog } from "#dms-ui/app/build/composables/containers/closingLayers";
|
|
3
4
|
import { isFloatingSaveBarShown } from "#dms-ui/app/build/composables/form/floatingSaveBars";
|
|
4
5
|
import { useGithubStarPrompt } from "../../composables/general/useGithubStarPrompt";
|
|
6
|
+
import { useActiveSidePanel } from "../../composables/layout/sidePanelState";
|
|
7
|
+
import { useSidebarState } from "./sidebarState";
|
|
5
8
|
|
|
6
9
|
const TITLE_ID = "dms-github-star-prompt-title";
|
|
7
10
|
const DESCRIPTION_ID = "dms-github-star-prompt-description";
|
|
@@ -9,6 +12,9 @@ const DESCRIPTION_ID = "dms-github-star-prompt-description";
|
|
|
9
12
|
const { t } = useI18n();
|
|
10
13
|
const { user } = useCurrentUser();
|
|
11
14
|
const toast = useToast();
|
|
15
|
+
const { open: isSidebarOpen } = useSidebarState();
|
|
16
|
+
const { panel: sidePanel } = useActiveSidePanel();
|
|
17
|
+
const isDialogOpen = useOpenDialog();
|
|
12
18
|
|
|
13
19
|
// Developers only: a production build, a client's dashboard included, never
|
|
14
20
|
// counts, stores or shows anything. The same flag gates the dev reload.
|
|
@@ -16,15 +22,21 @@ const { isDue, snooze, star, dismiss } = useGithubStarPrompt(
|
|
|
16
22
|
import.meta.env.DEV,
|
|
17
23
|
);
|
|
18
24
|
|
|
19
|
-
// The toaster stacks in the same corner,
|
|
20
|
-
//
|
|
21
|
-
//
|
|
25
|
+
// The toaster stacks in the same corner, a floating save bar sticks to the
|
|
26
|
+
// bottom of the panel, and the phone sidebar keeps its account menu trigger
|
|
27
|
+
// at the bottom of the screen: the prompt steps aside while any is up rather
|
|
28
|
+
// than cover it. The sidebar only opens as a drawer, below `lg`. It waits
|
|
29
|
+
// as well while a drawer, a modal or a side panel is open, whose footer or
|
|
30
|
+
// content it would float over, and comes back once they close.
|
|
22
31
|
const isShown = computed(
|
|
23
32
|
() =>
|
|
24
33
|
isDue.value &&
|
|
25
34
|
!!user.value &&
|
|
26
35
|
toast.toasts.value.length === 0 &&
|
|
27
|
-
!isFloatingSaveBarShown.value
|
|
36
|
+
!isFloatingSaveBarShown.value &&
|
|
37
|
+
!isSidebarOpen.value &&
|
|
38
|
+
!sidePanel.value &&
|
|
39
|
+
!isDialogOpen.value,
|
|
28
40
|
);
|
|
29
41
|
</script>
|
|
30
42
|
|
|
@@ -34,14 +46,13 @@ const isShown = computed(
|
|
|
34
46
|
width, rising into place like a toast. The buttons take the card's
|
|
35
47
|
full width, so the longer French label still fits beside "Later".
|
|
36
48
|
On a phone it tightens and drops the icon, so the text runs the full
|
|
37
|
-
width and covers less of the page.
|
|
38
|
-
open side panel, whose width the dashboard frame sets. -->
|
|
49
|
+
width and covers less of the page. -->
|
|
39
50
|
<div
|
|
40
51
|
v-if="isShown"
|
|
41
52
|
role="dialog"
|
|
42
53
|
:aria-labelledby="TITLE_ID"
|
|
43
54
|
:aria-describedby="DESCRIPTION_ID"
|
|
44
|
-
class="bg-default ring-accented fixed inset-x-3 bottom-3 z-50 rounded-(--dms-radius-card) p-3 shadow-(--dms-shadow-pop) ring transition duration-300 ease-out motion-reduce:transition-none sm:inset-x-auto sm:right-5 sm:bottom-5 sm:w-[380px] sm:p-3.5 sm:ps-4
|
|
55
|
+
class="bg-default ring-accented fixed inset-x-3 bottom-3 z-50 rounded-(--dms-radius-card) p-3 shadow-(--dms-shadow-pop) ring transition duration-300 ease-out motion-reduce:transition-none sm:inset-x-auto sm:right-5 sm:bottom-5 sm:w-[380px] sm:p-3.5 sm:ps-4 starting:translate-y-4 starting:opacity-0"
|
|
45
56
|
>
|
|
46
57
|
<div class="flex items-start gap-3 pe-6">
|
|
47
58
|
<DmsIconWell icon="i-ph-star" size="sm" class="max-sm:hidden" />
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
findServedQuickAction,
|
|
25
25
|
} from "#dms-ui/app/build/utils/dispatchQuickActionTarget";
|
|
26
26
|
import { DEFAULT_PAGE_HEADER_ACTIONS_ORDER } from "../../../composables/layout/usePageHeaderActions";
|
|
27
|
+
import { type PageRecord, withPageRecord } from "../../../utils/pageRecord";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* A button of the page header as the server serves it (`DefaultLayout({
|
|
@@ -43,6 +44,8 @@ export interface LayoutHeaderAction
|
|
|
43
44
|
buttonId?: string;
|
|
44
45
|
/** Place among the header's buttons, smallest first; `0` by default. */
|
|
45
46
|
order?: number;
|
|
47
|
+
/** Acts on the page's record: disabled while it loads, gone without it. */
|
|
48
|
+
requiresRecord?: boolean;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
interface PageHeaderActionBarProps {
|
|
@@ -52,6 +55,8 @@ interface PageHeaderActionBarProps {
|
|
|
52
55
|
* among the buttons: after every button of an order up to this one.
|
|
53
56
|
*/
|
|
54
57
|
slotOrder?: number;
|
|
58
|
+
/** The record the page shows, for the buttons acting on it. */
|
|
59
|
+
record?: PageRecord;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
interface ResolvedHeaderAction {
|
|
@@ -66,6 +71,7 @@ interface ResolvedHeaderAction {
|
|
|
66
71
|
|
|
67
72
|
const props = withDefaults(defineProps<PageHeaderActionBarProps>(), {
|
|
68
73
|
slotOrder: DEFAULT_PAGE_HEADER_ACTIONS_ORDER,
|
|
74
|
+
record: undefined,
|
|
69
75
|
});
|
|
70
76
|
|
|
71
77
|
const { processI18n } = useTranslation();
|
|
@@ -273,6 +279,8 @@ function lockForPreview(action: ResolvedHeaderAction): ResolvedHeaderAction {
|
|
|
273
279
|
|
|
274
280
|
const resolved = computed(() =>
|
|
275
281
|
props.actions
|
|
282
|
+
.map((action) => withPageRecord(action, props.record))
|
|
283
|
+
.filter((action): action is LayoutHeaderAction => action !== null)
|
|
276
284
|
.map(resolveAction)
|
|
277
285
|
.filter((action): action is ResolvedHeaderAction => action !== null)
|
|
278
286
|
.map(lockForPreview)
|
package/frontend-vue/layers/dms-layout/app/build/components/layout/PageHeaderActionsOutlet.vue
CHANGED
|
@@ -5,21 +5,34 @@ import PageHeaderActionBar, {
|
|
|
5
5
|
} from "./PageHeaderActionBar.vue";
|
|
6
6
|
import { injectPageHeaderActionsHost } from "../../../composables/layout/usePageHeaderActions";
|
|
7
7
|
import { useServedHeaderActions } from "../../../composables/layout/useServedHeaderActions";
|
|
8
|
+
import {
|
|
9
|
+
type PageRecordSource,
|
|
10
|
+
usePageRecord,
|
|
11
|
+
} from "../../../composables/layout/usePageRecord";
|
|
8
12
|
|
|
9
13
|
interface PageHeaderActionsOutletProps {
|
|
10
14
|
/** Header buttons declared by the backend page (`headerActions`). */
|
|
11
15
|
actions: LayoutHeaderAction[];
|
|
12
16
|
/** The page query the server resolved their availability for. */
|
|
13
17
|
servedQuery?: Record<string, string>;
|
|
18
|
+
/** The route parameters the server resolved their availability for. */
|
|
19
|
+
servedParams?: Record<string, string>;
|
|
20
|
+
/** The record the page shows (`record` of the layout). */
|
|
21
|
+
record?: PageRecordSource;
|
|
14
22
|
}
|
|
15
23
|
|
|
16
24
|
const props = withDefaults(defineProps<PageHeaderActionsOutletProps>(), {
|
|
17
25
|
servedQuery: undefined,
|
|
26
|
+
servedParams: undefined,
|
|
27
|
+
record: undefined,
|
|
18
28
|
});
|
|
19
29
|
|
|
30
|
+
const pageRecord = usePageRecord(() => props.record);
|
|
31
|
+
|
|
20
32
|
const actions = useServedHeaderActions({
|
|
21
33
|
actions: () => props.actions,
|
|
22
34
|
servedQuery: () => props.servedQuery,
|
|
35
|
+
servedParams: () => props.servedParams,
|
|
23
36
|
});
|
|
24
37
|
|
|
25
38
|
const ROOT_SELECTOR = "[data-dms-page-header-actions]";
|
|
@@ -69,6 +82,7 @@ const showsServerMarkup = computed(
|
|
|
69
82
|
<PageHeaderActionBar
|
|
70
83
|
:actions="actions"
|
|
71
84
|
:slot-order="host?.actionsOrder.value"
|
|
85
|
+
:record="pageRecord"
|
|
72
86
|
>
|
|
73
87
|
<component :is="pageActions" v-if="pageActions" />
|
|
74
88
|
</PageHeaderActionBar>
|
|
@@ -1,47 +1,52 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
/**
|
|
3
3
|
* The body of the side panel a `sidePanel` action target opens on a row (see
|
|
4
|
-
* `rowSidePanel.ts`). The DMS draws the header
|
|
5
|
-
*
|
|
6
|
-
* (Escape too). Below it, the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* `rowSidePanel.ts`). The DMS draws the header (`RowHeader`, shared with a
|
|
5
|
+
* row drawer): the title, the row's position among the rows the table shows,
|
|
6
|
+
* previous and next (J and K too) and close (Escape too). Below it, the
|
|
7
|
+
* module's component receives the row as a drawer's component does, mounted
|
|
8
|
+
* anew on each row. The position follows the table: a refresh or live rows
|
|
9
|
+
* that move it update it, and a row past the rows loaded (a deep link) is
|
|
10
|
+
* located in the table's whole result. A row the link names but its route answered 404
|
|
11
|
+
* for shows the "not found" state instead, with a close button.
|
|
11
12
|
*/
|
|
12
|
-
import { computed, onBeforeUnmount, onMounted } from "vue";
|
|
13
|
-
import
|
|
13
|
+
import { computed, onBeforeUnmount, onMounted, shallowRef, watch } from "vue";
|
|
14
|
+
import DmsRowHeader from "#dms-ui/app/build/components/containers/row/RowHeader.vue";
|
|
15
|
+
import DmsRowNotFound from "#dms-ui/app/build/components/containers/row/RowNotFound.vue";
|
|
14
16
|
import {
|
|
15
17
|
listenRowPanelClose,
|
|
16
18
|
listenRowSteps,
|
|
17
|
-
|
|
19
|
+
trackRowNavigation,
|
|
18
20
|
} from "#dms-ui/app/build/composables/actions/rowNavigation";
|
|
19
21
|
import {
|
|
20
22
|
closeRowSidePanel,
|
|
21
23
|
useRowSidePanelContent,
|
|
22
24
|
} from "../../composables/layout/rowSidePanel";
|
|
23
25
|
|
|
24
|
-
const DEFAULT_POSITION_KEY = "side_panel.position";
|
|
25
|
-
|
|
26
26
|
const { t } = useI18n();
|
|
27
|
-
const { processI18n } = useTranslation();
|
|
28
27
|
const content = useRowSidePanelContent();
|
|
29
28
|
|
|
30
|
-
const navigation =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
const navigation = shallowRef<RowNavigation>();
|
|
30
|
+
let stopNavigation: (() => void) | undefined;
|
|
31
|
+
watch(
|
|
32
|
+
content,
|
|
33
|
+
(current) => {
|
|
34
|
+
stopNavigation?.();
|
|
35
|
+
stopNavigation = undefined;
|
|
36
|
+
navigation.value = undefined;
|
|
37
|
+
if (!current?.row || !current.source) return;
|
|
38
|
+
stopNavigation = trackRowNavigation(
|
|
39
|
+
current.source,
|
|
40
|
+
current.row,
|
|
41
|
+
current.showRow,
|
|
42
|
+
(next) => {
|
|
43
|
+
navigation.value = next;
|
|
44
|
+
},
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
// At once: a second J right after the first steps from the row it opened.
|
|
48
|
+
{ immediate: true, flush: "sync" },
|
|
49
|
+
);
|
|
45
50
|
|
|
46
51
|
const componentProps = computed(() => ({
|
|
47
52
|
...content.value?.componentOptions,
|
|
@@ -53,16 +58,6 @@ const heading = computed(() => content.value?.rowTitle || content.value?.title);
|
|
|
53
58
|
|
|
54
59
|
const close = () => closeRowSidePanel();
|
|
55
60
|
|
|
56
|
-
const notFoundActions = computed(() => [
|
|
57
|
-
{
|
|
58
|
-
label: t("side_panel.close"),
|
|
59
|
-
icon: "i-ph-x",
|
|
60
|
-
color: "neutral" as const,
|
|
61
|
-
variant: "outline" as const,
|
|
62
|
-
onClick: close,
|
|
63
|
-
},
|
|
64
|
-
]);
|
|
65
|
-
|
|
66
61
|
let stopKeys: Array<() => void> = [];
|
|
67
62
|
|
|
68
63
|
onMounted(() => {
|
|
@@ -76,6 +71,7 @@ onMounted(() => {
|
|
|
76
71
|
// longer open.
|
|
77
72
|
onBeforeUnmount(() => {
|
|
78
73
|
stopKeys.forEach((stop) => stop());
|
|
74
|
+
stopNavigation?.();
|
|
79
75
|
close();
|
|
80
76
|
});
|
|
81
77
|
</script>
|
|
@@ -85,45 +81,12 @@ onBeforeUnmount(() => {
|
|
|
85
81
|
<header
|
|
86
82
|
class="border-default flex shrink-0 items-start gap-2 border-b py-3 ps-4 pe-3"
|
|
87
83
|
>
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<p
|
|
95
|
-
v-if="position"
|
|
96
|
-
data-dms-row-side-panel-position
|
|
97
|
-
class="text-muted mt-0.5 text-[12.5px] tabular-nums"
|
|
98
|
-
>
|
|
99
|
-
{{ position }}
|
|
100
|
-
</p>
|
|
101
|
-
</div>
|
|
102
|
-
<div class="flex shrink-0 items-center gap-0.5">
|
|
103
|
-
<template v-if="navigation">
|
|
104
|
-
<UButton
|
|
105
|
-
data-dms-row-side-panel-prev
|
|
106
|
-
icon="i-ph-caret-up"
|
|
107
|
-
color="neutral"
|
|
108
|
-
variant="ghost"
|
|
109
|
-
size="sm"
|
|
110
|
-
square
|
|
111
|
-
:aria-label="t('side_panel.previous')"
|
|
112
|
-
:disabled="!navigation.hasPrev"
|
|
113
|
-
@click="navigation.prev()"
|
|
114
|
-
/>
|
|
115
|
-
<UButton
|
|
116
|
-
data-dms-row-side-panel-next
|
|
117
|
-
icon="i-ph-caret-down"
|
|
118
|
-
color="neutral"
|
|
119
|
-
variant="ghost"
|
|
120
|
-
size="sm"
|
|
121
|
-
square
|
|
122
|
-
:aria-label="t('side_panel.next')"
|
|
123
|
-
:disabled="!navigation.hasNext"
|
|
124
|
-
@click="navigation.next()"
|
|
125
|
-
/>
|
|
126
|
-
</template>
|
|
84
|
+
<DmsRowHeader
|
|
85
|
+
part="dms-row-side-panel"
|
|
86
|
+
:heading="heading"
|
|
87
|
+
:position-label="content.positionLabel"
|
|
88
|
+
:navigation="navigation"
|
|
89
|
+
>
|
|
127
90
|
<UButton
|
|
128
91
|
data-dms-row-side-panel-close
|
|
129
92
|
icon="i-ph-x"
|
|
@@ -134,17 +97,15 @@ onBeforeUnmount(() => {
|
|
|
134
97
|
:aria-label="t('side_panel.close')"
|
|
135
98
|
@click="close"
|
|
136
99
|
/>
|
|
137
|
-
</
|
|
100
|
+
</DmsRowHeader>
|
|
138
101
|
</header>
|
|
139
102
|
<div class="min-h-0 flex-1 overflow-y-auto p-4">
|
|
140
|
-
<
|
|
103
|
+
<DmsRowNotFound
|
|
141
104
|
v-if="content.notFound"
|
|
142
105
|
data-dms-row-side-panel-not-found
|
|
143
|
-
variant="no-result"
|
|
144
106
|
:title="content.notFound.title"
|
|
145
107
|
:description="content.notFound.description"
|
|
146
|
-
|
|
147
|
-
class="py-10"
|
|
108
|
+
@close="close"
|
|
148
109
|
/>
|
|
149
110
|
<Suspense v-else>
|
|
150
111
|
<component
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import UserIdentity from "./UserIdentity.vue";
|
|
3
|
+
import { useSidebarState } from "./sidebarState";
|
|
3
4
|
import type { DropdownMenuItem } from "@nuxt/ui";
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
@@ -27,11 +28,32 @@ const COLOR_MODE_ENTRIES: ColorModeEntry[] = [
|
|
|
27
28
|
];
|
|
28
29
|
|
|
29
30
|
const { t, locale } = useI18n();
|
|
31
|
+
const route = useDmsRoute();
|
|
30
32
|
const { user } = useCurrentUser();
|
|
31
33
|
const { logout } = useLogout();
|
|
32
34
|
const colorModePreference = useColorModePreference();
|
|
33
35
|
const { uniqueLocales } = useUniqueLocales();
|
|
34
36
|
const { changeLanguage } = useUserLanguage();
|
|
37
|
+
const { open: sidebarOpen } = useSidebarState();
|
|
38
|
+
|
|
39
|
+
// The picture the profile saved, read from the session user: a profile save
|
|
40
|
+
// refreshes that user, so a new picture shows here at once.
|
|
41
|
+
const avatarUrls = useFileReadUrls();
|
|
42
|
+
const avatarKey = computed(() => user.value?.avatar?.key);
|
|
43
|
+
const avatarSrc = computed(() =>
|
|
44
|
+
avatarKey.value ? avatarUrls.getUrl(avatarKey.value) : undefined,
|
|
45
|
+
);
|
|
46
|
+
watch(avatarKey, (key) => key && void avatarUrls.resolve(key), {
|
|
47
|
+
immediate: true,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// The settings have no sidebar entry: their only way in is this menu, so its
|
|
51
|
+
// trigger is drawn active while a settings page is open.
|
|
52
|
+
const isOnSettings = computed(
|
|
53
|
+
() =>
|
|
54
|
+
route.path === SETTINGS_ROUTE ||
|
|
55
|
+
route.path.startsWith(`${SETTINGS_ROUTE}/`),
|
|
56
|
+
);
|
|
35
57
|
|
|
36
58
|
// v2 user menu: account links, then the per-user preferences as submenus,
|
|
37
59
|
// then logging out.
|
|
@@ -67,6 +89,11 @@ const menuItems = computed<DropdownMenuItem[][]>(() => [
|
|
|
67
89
|
label: t(entry.labelKey),
|
|
68
90
|
icon: entry.icon,
|
|
69
91
|
to: entry.to,
|
|
92
|
+
// The menu renders in a portal, outside the sidebar whose link clicks
|
|
93
|
+
// close the phone drawer: its own entries close it themselves.
|
|
94
|
+
onSelect: () => {
|
|
95
|
+
sidebarOpen.value = false;
|
|
96
|
+
},
|
|
70
97
|
})),
|
|
71
98
|
preferenceItems.value,
|
|
72
99
|
[
|
|
@@ -91,12 +118,25 @@ const menuItems = computed<DropdownMenuItem[][]>(() => [
|
|
|
91
118
|
<button
|
|
92
119
|
type="button"
|
|
93
120
|
class="hover:bg-elevated data-[state=open]:bg-elevated flex w-full items-center gap-2.5 rounded-md p-1.5 text-start transition-colors"
|
|
94
|
-
:class="{
|
|
121
|
+
:class="{
|
|
122
|
+
'justify-center': props.collapsed,
|
|
123
|
+
'bg-elevated': isOnSettings,
|
|
124
|
+
}"
|
|
95
125
|
:aria-label="user?.name"
|
|
126
|
+
:data-active="isOnSettings || undefined"
|
|
96
127
|
>
|
|
97
|
-
<UAvatar
|
|
128
|
+
<UAvatar
|
|
129
|
+
v-if="props.collapsed"
|
|
130
|
+
:src="avatarSrc"
|
|
131
|
+
:alt="user?.name"
|
|
132
|
+
size="sm"
|
|
133
|
+
/>
|
|
98
134
|
<template v-else>
|
|
99
|
-
<UserIdentity
|
|
135
|
+
<UserIdentity
|
|
136
|
+
:name="user?.name"
|
|
137
|
+
:email="user?.email"
|
|
138
|
+
:avatar-src="avatarSrc"
|
|
139
|
+
/>
|
|
100
140
|
<UIcon :name="TRIGGER_ICON" class="text-dimmed size-4 shrink-0" />
|
|
101
141
|
</template>
|
|
102
142
|
</button>
|
|
@@ -105,6 +145,7 @@ const menuItems = computed<DropdownMenuItem[][]>(() => [
|
|
|
105
145
|
<UserIdentity
|
|
106
146
|
:name="user?.name"
|
|
107
147
|
:email="user?.email"
|
|
148
|
+
:avatar-src="avatarSrc"
|
|
108
149
|
avatar-size="md"
|
|
109
150
|
class="border-default border-b px-2.5 py-2.5"
|
|
110
151
|
/>
|
|
@@ -1,25 +1,33 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { AvatarProps } from "@nuxt/ui";
|
|
3
3
|
|
|
4
|
-
// The signed-in user as the shell shows them:
|
|
5
|
-
// the e-mail in mono (the sidebar menu's trigger and
|
|
4
|
+
// The signed-in user as the shell shows them: their picture (initials
|
|
5
|
+
// without one), name, then the e-mail in mono (the sidebar menu's trigger and
|
|
6
|
+
// its header).
|
|
6
7
|
|
|
7
8
|
interface UserIdentityProps {
|
|
8
9
|
name?: string;
|
|
9
10
|
email?: string;
|
|
11
|
+
avatarSrc?: string;
|
|
10
12
|
avatarSize?: AvatarProps["size"];
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
const props = withDefaults(defineProps<UserIdentityProps>(), {
|
|
14
16
|
name: undefined,
|
|
15
17
|
email: undefined,
|
|
18
|
+
avatarSrc: undefined,
|
|
16
19
|
avatarSize: "sm",
|
|
17
20
|
});
|
|
18
21
|
</script>
|
|
19
22
|
|
|
20
23
|
<template>
|
|
21
24
|
<span class="flex min-w-0 flex-1 items-center gap-2.5">
|
|
22
|
-
<UAvatar
|
|
25
|
+
<UAvatar
|
|
26
|
+
:src="props.avatarSrc"
|
|
27
|
+
:alt="props.name"
|
|
28
|
+
:size="props.avatarSize"
|
|
29
|
+
class="shrink-0"
|
|
30
|
+
/>
|
|
23
31
|
<span class="flex min-w-0 flex-1 flex-col">
|
|
24
32
|
<span
|
|
25
33
|
class="text-highlighted truncate text-[13px] leading-tight font-semibold"
|