@multiplatform.one/backoffice 6.3.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/LICENSE +201 -0
- package/README.md +310 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.cjs +95 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.native.js +106 -0
- package/dist/cjs/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/cjs/chrome/CommandPalette.cjs +453 -0
- package/dist/cjs/chrome/CommandPalette.native.js +505 -0
- package/dist/cjs/chrome/CommandPalette.native.js.map +1 -0
- package/dist/cjs/chrome/HelpMenu.cjs +131 -0
- package/dist/cjs/chrome/HelpMenu.native.js +145 -0
- package/dist/cjs/chrome/HelpMenu.native.js.map +1 -0
- package/dist/cjs/chrome/NotificationsButton.cjs +112 -0
- package/dist/cjs/chrome/NotificationsButton.native.js +115 -0
- package/dist/cjs/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/cjs/chrome/UserMenu.cjs +158 -0
- package/dist/cjs/chrome/UserMenu.native.js +186 -0
- package/dist/cjs/chrome/UserMenu.native.js.map +1 -0
- package/dist/cjs/chrome/awesomebar-data.cjs +173 -0
- package/dist/cjs/chrome/awesomebar-data.native.js +233 -0
- package/dist/cjs/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/cjs/chrome/command-palette-model.cjs +208 -0
- package/dist/cjs/chrome/command-palette-model.native.js +301 -0
- package/dist/cjs/chrome/command-palette-model.native.js.map +1 -0
- package/dist/cjs/chrome/help-about-dialog.cjs +136 -0
- package/dist/cjs/chrome/help-about-dialog.native.js +146 -0
- package/dist/cjs/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.cjs +155 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.native.js +168 -0
- package/dist/cjs/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-data.cjs +190 -0
- package/dist/cjs/chrome/notifications-data.native.js +271 -0
- package/dist/cjs/chrome/notifications-data.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-panel.cjs +171 -0
- package/dist/cjs/chrome/notifications-panel.native.js +189 -0
- package/dist/cjs/chrome/notifications-panel.native.js.map +1 -0
- package/dist/cjs/chrome/notifications-utils.cjs +43 -0
- package/dist/cjs/chrome/notifications-utils.native.js +46 -0
- package/dist/cjs/chrome/notifications-utils.native.js.map +1 -0
- package/dist/cjs/chrome/shortcuts.cjs +58 -0
- package/dist/cjs/chrome/shortcuts.native.js +72 -0
- package/dist/cjs/chrome/shortcuts.native.js.map +1 -0
- package/dist/cjs/chrome/user-session.cjs +100 -0
- package/dist/cjs/chrome/user-session.native.js +120 -0
- package/dist/cjs/chrome/user-session.native.js.map +1 -0
- package/dist/cjs/config/BackofficeProvider.cjs +164 -0
- package/dist/cjs/config/BackofficeProvider.native.js +217 -0
- package/dist/cjs/config/BackofficeProvider.native.js.map +1 -0
- package/dist/cjs/config/capabilities.cjs +123 -0
- package/dist/cjs/config/capabilities.native.js +155 -0
- package/dist/cjs/config/capabilities.native.js.map +1 -0
- package/dist/cjs/config/events.cjs +18 -0
- package/dist/cjs/config/events.native.js +21 -0
- package/dist/cjs/config/events.native.js.map +1 -0
- package/dist/cjs/config/slots.cjs +18 -0
- package/dist/cjs/config/slots.native.js +21 -0
- package/dist/cjs/config/slots.native.js.map +1 -0
- package/dist/cjs/i18n/en.cjs +101 -0
- package/dist/cjs/i18n/en.native.js +104 -0
- package/dist/cjs/i18n/en.native.js.map +1 -0
- package/dist/cjs/i18n/index.cjs +77 -0
- package/dist/cjs/i18n/index.native.js +102 -0
- package/dist/cjs/i18n/index.native.js.map +1 -0
- package/dist/cjs/index.cjs +109 -0
- package/dist/cjs/index.native.js +112 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/navigation/navigator.cjs +144 -0
- package/dist/cjs/navigation/navigator.native.js +307 -0
- package/dist/cjs/navigation/navigator.native.js.map +1 -0
- package/dist/cjs/navigation/paths.cjs +103 -0
- package/dist/cjs/navigation/paths.native.js +143 -0
- package/dist/cjs/navigation/paths.native.js.map +1 -0
- package/dist/cjs/oneAdapter/index.cjs +53 -0
- package/dist/cjs/oneAdapter/index.native.js +64 -0
- package/dist/cjs/oneAdapter/index.native.js.map +1 -0
- package/dist/cjs/shared/useFrappeApp.cjs +56 -0
- package/dist/cjs/shared/useFrappeApp.native.js +60 -0
- package/dist/cjs/shared/useFrappeApp.native.js.map +1 -0
- package/dist/cjs/shell/BackofficeShell.cjs +194 -0
- package/dist/cjs/shell/BackofficeShell.native.js +223 -0
- package/dist/cjs/shell/BackofficeShell.native.js.map +1 -0
- package/dist/cjs/shell/WorkspaceSidebar.cjs +115 -0
- package/dist/cjs/shell/WorkspaceSidebar.native.js +143 -0
- package/dist/cjs/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/cjs/shell/useWorkspaces.cjs +131 -0
- package/dist/cjs/shell/useWorkspaces.native.js +173 -0
- package/dist/cjs/shell/useWorkspaces.native.js.map +1 -0
- package/dist/cjs/shell/workspaceIcons.cjs +64 -0
- package/dist/cjs/shell/workspaceIcons.native.js +67 -0
- package/dist/cjs/shell/workspaceIcons.native.js.map +1 -0
- package/dist/esm/chrome/BackofficeAwesomebar.mjs +70 -0
- package/dist/esm/chrome/BackofficeAwesomebar.mjs.map +1 -0
- package/dist/esm/chrome/BackofficeAwesomebar.native.js +78 -0
- package/dist/esm/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/esm/chrome/CommandPalette.mjs +428 -0
- package/dist/esm/chrome/CommandPalette.mjs.map +1 -0
- package/dist/esm/chrome/CommandPalette.native.js +477 -0
- package/dist/esm/chrome/CommandPalette.native.js.map +1 -0
- package/dist/esm/chrome/HelpMenu.mjs +106 -0
- package/dist/esm/chrome/HelpMenu.mjs.map +1 -0
- package/dist/esm/chrome/HelpMenu.native.js +117 -0
- package/dist/esm/chrome/HelpMenu.native.js.map +1 -0
- package/dist/esm/chrome/NotificationsButton.mjs +87 -0
- package/dist/esm/chrome/NotificationsButton.mjs.map +1 -0
- package/dist/esm/chrome/NotificationsButton.native.js +87 -0
- package/dist/esm/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/esm/chrome/UserMenu.mjs +133 -0
- package/dist/esm/chrome/UserMenu.mjs.map +1 -0
- package/dist/esm/chrome/UserMenu.native.js +147 -0
- package/dist/esm/chrome/UserMenu.native.js.map +1 -0
- package/dist/esm/chrome/awesomebar-data.mjs +144 -0
- package/dist/esm/chrome/awesomebar-data.mjs.map +1 -0
- package/dist/esm/chrome/awesomebar-data.native.js +190 -0
- package/dist/esm/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/esm/chrome/command-palette-model.mjs +183 -0
- package/dist/esm/chrome/command-palette-model.mjs.map +1 -0
- package/dist/esm/chrome/command-palette-model.native.js +273 -0
- package/dist/esm/chrome/command-palette-model.native.js.map +1 -0
- package/dist/esm/chrome/help-about-dialog.mjs +111 -0
- package/dist/esm/chrome/help-about-dialog.mjs.map +1 -0
- package/dist/esm/chrome/help-about-dialog.native.js +118 -0
- package/dist/esm/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/esm/chrome/help-shortcuts-dialog.mjs +130 -0
- package/dist/esm/chrome/help-shortcuts-dialog.mjs.map +1 -0
- package/dist/esm/chrome/help-shortcuts-dialog.native.js +140 -0
- package/dist/esm/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/esm/chrome/notifications-data.mjs +165 -0
- package/dist/esm/chrome/notifications-data.mjs.map +1 -0
- package/dist/esm/chrome/notifications-data.native.js +232 -0
- package/dist/esm/chrome/notifications-data.native.js.map +1 -0
- package/dist/esm/chrome/notifications-panel.mjs +146 -0
- package/dist/esm/chrome/notifications-panel.mjs.map +1 -0
- package/dist/esm/chrome/notifications-panel.native.js +161 -0
- package/dist/esm/chrome/notifications-panel.native.js.map +1 -0
- package/dist/esm/chrome/notifications-utils.mjs +17 -0
- package/dist/esm/chrome/notifications-utils.mjs.map +1 -0
- package/dist/esm/chrome/notifications-utils.native.js +17 -0
- package/dist/esm/chrome/notifications-utils.native.js.map +1 -0
- package/dist/esm/chrome/shortcuts.mjs +33 -0
- package/dist/esm/chrome/shortcuts.mjs.map +1 -0
- package/dist/esm/chrome/shortcuts.native.js +44 -0
- package/dist/esm/chrome/shortcuts.native.js.map +1 -0
- package/dist/esm/chrome/user-session.mjs +73 -0
- package/dist/esm/chrome/user-session.mjs.map +1 -0
- package/dist/esm/chrome/user-session.native.js +79 -0
- package/dist/esm/chrome/user-session.native.js.map +1 -0
- package/dist/esm/config/BackofficeProvider.mjs +132 -0
- package/dist/esm/config/BackofficeProvider.mjs.map +1 -0
- package/dist/esm/config/BackofficeProvider.native.js +171 -0
- package/dist/esm/config/BackofficeProvider.native.js.map +1 -0
- package/dist/esm/config/capabilities.mjs +97 -0
- package/dist/esm/config/capabilities.mjs.map +1 -0
- package/dist/esm/config/capabilities.native.js +126 -0
- package/dist/esm/config/capabilities.native.js.map +1 -0
- package/dist/esm/config/events.mjs +2 -0
- package/dist/esm/config/events.mjs.map +1 -0
- package/dist/esm/config/events.native.js +2 -0
- package/dist/esm/config/events.native.js.map +1 -0
- package/dist/esm/config/slots.mjs +2 -0
- package/dist/esm/config/slots.mjs.map +1 -0
- package/dist/esm/config/slots.native.js +2 -0
- package/dist/esm/config/slots.native.js.map +1 -0
- package/dist/esm/i18n/en.mjs +76 -0
- package/dist/esm/i18n/en.mjs.map +1 -0
- package/dist/esm/i18n/en.native.js +76 -0
- package/dist/esm/i18n/en.native.js.map +1 -0
- package/dist/esm/i18n/index.mjs +40 -0
- package/dist/esm/i18n/index.mjs.map +1 -0
- package/dist/esm/i18n/index.native.js +62 -0
- package/dist/esm/i18n/index.native.js.map +1 -0
- package/dist/esm/index.mjs +26 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +26 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/navigation/navigator.mjs +115 -0
- package/dist/esm/navigation/navigator.mjs.map +1 -0
- package/dist/esm/navigation/navigator.native.js +275 -0
- package/dist/esm/navigation/navigator.native.js.map +1 -0
- package/dist/esm/navigation/paths.mjs +66 -0
- package/dist/esm/navigation/paths.mjs.map +1 -0
- package/dist/esm/navigation/paths.native.js +103 -0
- package/dist/esm/navigation/paths.native.js.map +1 -0
- package/dist/esm/oneAdapter/index.mjs +28 -0
- package/dist/esm/oneAdapter/index.mjs.map +1 -0
- package/dist/esm/oneAdapter/index.native.js +36 -0
- package/dist/esm/oneAdapter/index.native.js.map +1 -0
- package/dist/esm/shared/useFrappeApp.mjs +31 -0
- package/dist/esm/shared/useFrappeApp.mjs.map +1 -0
- package/dist/esm/shared/useFrappeApp.native.js +32 -0
- package/dist/esm/shared/useFrappeApp.native.js.map +1 -0
- package/dist/esm/shell/BackofficeShell.mjs +169 -0
- package/dist/esm/shell/BackofficeShell.mjs.map +1 -0
- package/dist/esm/shell/BackofficeShell.native.js +195 -0
- package/dist/esm/shell/BackofficeShell.native.js.map +1 -0
- package/dist/esm/shell/WorkspaceSidebar.mjs +89 -0
- package/dist/esm/shell/WorkspaceSidebar.mjs.map +1 -0
- package/dist/esm/shell/WorkspaceSidebar.native.js +114 -0
- package/dist/esm/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/esm/shell/useWorkspaces.mjs +104 -0
- package/dist/esm/shell/useWorkspaces.mjs.map +1 -0
- package/dist/esm/shell/useWorkspaces.native.js +143 -0
- package/dist/esm/shell/useWorkspaces.native.js.map +1 -0
- package/dist/esm/shell/workspaceIcons.mjs +39 -0
- package/dist/esm/shell/workspaceIcons.mjs.map +1 -0
- package/dist/esm/shell/workspaceIcons.native.js +39 -0
- package/dist/esm/shell/workspaceIcons.native.js.map +1 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.mjs +70 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.mjs.map +1 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.native.js +106 -0
- package/dist/jsx/chrome/BackofficeAwesomebar.native.js.map +1 -0
- package/dist/jsx/chrome/CommandPalette.mjs +428 -0
- package/dist/jsx/chrome/CommandPalette.mjs.map +1 -0
- package/dist/jsx/chrome/CommandPalette.native.js +505 -0
- package/dist/jsx/chrome/CommandPalette.native.js.map +1 -0
- package/dist/jsx/chrome/HelpMenu.mjs +106 -0
- package/dist/jsx/chrome/HelpMenu.mjs.map +1 -0
- package/dist/jsx/chrome/HelpMenu.native.js +145 -0
- package/dist/jsx/chrome/HelpMenu.native.js.map +1 -0
- package/dist/jsx/chrome/NotificationsButton.mjs +87 -0
- package/dist/jsx/chrome/NotificationsButton.mjs.map +1 -0
- package/dist/jsx/chrome/NotificationsButton.native.js +115 -0
- package/dist/jsx/chrome/NotificationsButton.native.js.map +1 -0
- package/dist/jsx/chrome/UserMenu.mjs +133 -0
- package/dist/jsx/chrome/UserMenu.mjs.map +1 -0
- package/dist/jsx/chrome/UserMenu.native.js +186 -0
- package/dist/jsx/chrome/UserMenu.native.js.map +1 -0
- package/dist/jsx/chrome/awesomebar-data.mjs +144 -0
- package/dist/jsx/chrome/awesomebar-data.mjs.map +1 -0
- package/dist/jsx/chrome/awesomebar-data.native.js +233 -0
- package/dist/jsx/chrome/awesomebar-data.native.js.map +1 -0
- package/dist/jsx/chrome/command-palette-model.mjs +183 -0
- package/dist/jsx/chrome/command-palette-model.mjs.map +1 -0
- package/dist/jsx/chrome/command-palette-model.native.js +301 -0
- package/dist/jsx/chrome/command-palette-model.native.js.map +1 -0
- package/dist/jsx/chrome/help-about-dialog.mjs +111 -0
- package/dist/jsx/chrome/help-about-dialog.mjs.map +1 -0
- package/dist/jsx/chrome/help-about-dialog.native.js +146 -0
- package/dist/jsx/chrome/help-about-dialog.native.js.map +1 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.mjs +130 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.mjs.map +1 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.native.js +168 -0
- package/dist/jsx/chrome/help-shortcuts-dialog.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-data.mjs +165 -0
- package/dist/jsx/chrome/notifications-data.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-data.native.js +271 -0
- package/dist/jsx/chrome/notifications-data.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-panel.mjs +146 -0
- package/dist/jsx/chrome/notifications-panel.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-panel.native.js +189 -0
- package/dist/jsx/chrome/notifications-panel.native.js.map +1 -0
- package/dist/jsx/chrome/notifications-utils.mjs +17 -0
- package/dist/jsx/chrome/notifications-utils.mjs.map +1 -0
- package/dist/jsx/chrome/notifications-utils.native.js +46 -0
- package/dist/jsx/chrome/notifications-utils.native.js.map +1 -0
- package/dist/jsx/chrome/shortcuts.mjs +33 -0
- package/dist/jsx/chrome/shortcuts.mjs.map +1 -0
- package/dist/jsx/chrome/shortcuts.native.js +72 -0
- package/dist/jsx/chrome/shortcuts.native.js.map +1 -0
- package/dist/jsx/chrome/user-session.mjs +73 -0
- package/dist/jsx/chrome/user-session.mjs.map +1 -0
- package/dist/jsx/chrome/user-session.native.js +120 -0
- package/dist/jsx/chrome/user-session.native.js.map +1 -0
- package/dist/jsx/config/BackofficeProvider.mjs +132 -0
- package/dist/jsx/config/BackofficeProvider.mjs.map +1 -0
- package/dist/jsx/config/BackofficeProvider.native.js +217 -0
- package/dist/jsx/config/BackofficeProvider.native.js.map +1 -0
- package/dist/jsx/config/capabilities.mjs +97 -0
- package/dist/jsx/config/capabilities.mjs.map +1 -0
- package/dist/jsx/config/capabilities.native.js +155 -0
- package/dist/jsx/config/capabilities.native.js.map +1 -0
- package/dist/jsx/config/events.mjs +2 -0
- package/dist/jsx/config/events.mjs.map +1 -0
- package/dist/jsx/config/events.native.js +21 -0
- package/dist/jsx/config/events.native.js.map +1 -0
- package/dist/jsx/config/slots.mjs +2 -0
- package/dist/jsx/config/slots.mjs.map +1 -0
- package/dist/jsx/config/slots.native.js +21 -0
- package/dist/jsx/config/slots.native.js.map +1 -0
- package/dist/jsx/i18n/en.mjs +76 -0
- package/dist/jsx/i18n/en.mjs.map +1 -0
- package/dist/jsx/i18n/en.native.js +104 -0
- package/dist/jsx/i18n/en.native.js.map +1 -0
- package/dist/jsx/i18n/index.mjs +40 -0
- package/dist/jsx/i18n/index.mjs.map +1 -0
- package/dist/jsx/i18n/index.native.js +102 -0
- package/dist/jsx/i18n/index.native.js.map +1 -0
- package/dist/jsx/index.js +26 -0
- package/dist/jsx/index.js.map +1 -0
- package/dist/jsx/index.mjs +26 -0
- package/dist/jsx/index.mjs.map +1 -0
- package/dist/jsx/index.native.js +112 -0
- package/dist/jsx/index.native.js.map +1 -0
- package/dist/jsx/navigation/navigator.mjs +115 -0
- package/dist/jsx/navigation/navigator.mjs.map +1 -0
- package/dist/jsx/navigation/navigator.native.js +307 -0
- package/dist/jsx/navigation/navigator.native.js.map +1 -0
- package/dist/jsx/navigation/paths.mjs +66 -0
- package/dist/jsx/navigation/paths.mjs.map +1 -0
- package/dist/jsx/navigation/paths.native.js +143 -0
- package/dist/jsx/navigation/paths.native.js.map +1 -0
- package/dist/jsx/oneAdapter/index.mjs +28 -0
- package/dist/jsx/oneAdapter/index.mjs.map +1 -0
- package/dist/jsx/oneAdapter/index.native.js +64 -0
- package/dist/jsx/oneAdapter/index.native.js.map +1 -0
- package/dist/jsx/shared/useFrappeApp.mjs +31 -0
- package/dist/jsx/shared/useFrappeApp.mjs.map +1 -0
- package/dist/jsx/shared/useFrappeApp.native.js +60 -0
- package/dist/jsx/shared/useFrappeApp.native.js.map +1 -0
- package/dist/jsx/shell/BackofficeShell.mjs +169 -0
- package/dist/jsx/shell/BackofficeShell.mjs.map +1 -0
- package/dist/jsx/shell/BackofficeShell.native.js +223 -0
- package/dist/jsx/shell/BackofficeShell.native.js.map +1 -0
- package/dist/jsx/shell/WorkspaceSidebar.mjs +89 -0
- package/dist/jsx/shell/WorkspaceSidebar.mjs.map +1 -0
- package/dist/jsx/shell/WorkspaceSidebar.native.js +143 -0
- package/dist/jsx/shell/WorkspaceSidebar.native.js.map +1 -0
- package/dist/jsx/shell/useWorkspaces.mjs +104 -0
- package/dist/jsx/shell/useWorkspaces.mjs.map +1 -0
- package/dist/jsx/shell/useWorkspaces.native.js +173 -0
- package/dist/jsx/shell/useWorkspaces.native.js.map +1 -0
- package/dist/jsx/shell/workspaceIcons.mjs +39 -0
- package/dist/jsx/shell/workspaceIcons.mjs.map +1 -0
- package/dist/jsx/shell/workspaceIcons.native.js +67 -0
- package/dist/jsx/shell/workspaceIcons.native.js.map +1 -0
- package/package.json +123 -0
- package/src/chrome/BackofficeAwesomebar.tsx +89 -0
- package/src/chrome/CommandPalette.spec.tsx +252 -0
- package/src/chrome/CommandPalette.tsx +520 -0
- package/src/chrome/HelpMenu.tsx +119 -0
- package/src/chrome/NotificationsButton.tsx +87 -0
- package/src/chrome/UserMenu.tsx +173 -0
- package/src/chrome/awesomebar-data.tsx +252 -0
- package/src/chrome/command-palette-model.ts +291 -0
- package/src/chrome/help-about-dialog.tsx +130 -0
- package/src/chrome/help-shortcuts-dialog.tsx +144 -0
- package/src/chrome/notifications-data.tsx +287 -0
- package/src/chrome/notifications-panel.tsx +175 -0
- package/src/chrome/notifications-utils.tsx +44 -0
- package/src/chrome/shortcuts.ts +53 -0
- package/src/chrome/user-session.tsx +116 -0
- package/src/config/BackofficeProvider.spec.tsx +126 -0
- package/src/config/BackofficeProvider.tsx +315 -0
- package/src/config/capabilities.ts +172 -0
- package/src/config/events.ts +19 -0
- package/src/config/slots.ts +28 -0
- package/src/i18n/en.ts +83 -0
- package/src/i18n/index.ts +69 -0
- package/src/index.ts +150 -0
- package/src/navigation/navigator.spec.ts +106 -0
- package/src/navigation/navigator.ts +209 -0
- package/src/navigation/paths.ts +146 -0
- package/src/oneAdapter/index.tsx +61 -0
- package/src/shared/useFrappeApp.ts +39 -0
- package/src/shell/BackofficeShell.tsx +222 -0
- package/src/shell/WorkspaceSidebar.tsx +119 -0
- package/src/shell/useWorkspaces.ts +202 -0
- package/src/shell/workspaceIcons.ts +76 -0
- package/types/chrome/BackofficeAwesomebar.d.ts +12 -0
- package/types/chrome/BackofficeAwesomebar.d.ts.map +1 -0
- package/types/chrome/CommandPalette.d.ts +6 -0
- package/types/chrome/CommandPalette.d.ts.map +1 -0
- package/types/chrome/HelpMenu.d.ts +2 -0
- package/types/chrome/HelpMenu.d.ts.map +1 -0
- package/types/chrome/NotificationsButton.d.ts +2 -0
- package/types/chrome/NotificationsButton.d.ts.map +1 -0
- package/types/chrome/UserMenu.d.ts +6 -0
- package/types/chrome/UserMenu.d.ts.map +1 -0
- package/types/chrome/awesomebar-data.d.ts +52 -0
- package/types/chrome/awesomebar-data.d.ts.map +1 -0
- package/types/chrome/command-palette-model.d.ts +47 -0
- package/types/chrome/command-palette-model.d.ts.map +1 -0
- package/types/chrome/help-about-dialog.d.ts +12 -0
- package/types/chrome/help-about-dialog.d.ts.map +1 -0
- package/types/chrome/help-shortcuts-dialog.d.ts +6 -0
- package/types/chrome/help-shortcuts-dialog.d.ts.map +1 -0
- package/types/chrome/notifications-data.d.ts +34 -0
- package/types/chrome/notifications-data.d.ts.map +1 -0
- package/types/chrome/notifications-panel.d.ts +11 -0
- package/types/chrome/notifications-panel.d.ts.map +1 -0
- package/types/chrome/notifications-utils.d.ts +21 -0
- package/types/chrome/notifications-utils.d.ts.map +1 -0
- package/types/chrome/shortcuts.d.ts +6 -0
- package/types/chrome/shortcuts.d.ts.map +1 -0
- package/types/chrome/user-session.d.ts +19 -0
- package/types/chrome/user-session.d.ts.map +1 -0
- package/types/config/BackofficeProvider.d.ts +128 -0
- package/types/config/BackofficeProvider.d.ts.map +1 -0
- package/types/config/capabilities.d.ts +109 -0
- package/types/config/capabilities.d.ts.map +1 -0
- package/types/config/events.d.ts +39 -0
- package/types/config/events.d.ts.map +1 -0
- package/types/config/slots.d.ts +32 -0
- package/types/config/slots.d.ts.map +1 -0
- package/types/i18n/en.d.ts +83 -0
- package/types/i18n/en.d.ts.map +1 -0
- package/types/i18n/index.d.ts +27 -0
- package/types/i18n/index.d.ts.map +1 -0
- package/types/index.d.ts +55 -0
- package/types/index.d.ts.map +1 -0
- package/types/navigation/navigator.d.ts +98 -0
- package/types/navigation/navigator.d.ts.map +1 -0
- package/types/navigation/paths.d.ts +60 -0
- package/types/navigation/paths.d.ts.map +1 -0
- package/types/oneAdapter/index.d.ts +8 -0
- package/types/oneAdapter/index.d.ts.map +1 -0
- package/types/shared/useFrappeApp.d.ts +10 -0
- package/types/shared/useFrappeApp.d.ts.map +1 -0
- package/types/shell/BackofficeShell.d.ts +10 -0
- package/types/shell/BackofficeShell.d.ts.map +1 -0
- package/types/shell/WorkspaceSidebar.d.ts +9 -0
- package/types/shell/WorkspaceSidebar.d.ts.map +1 -0
- package/types/shell/useWorkspaces.d.ts +43 -0
- package/types/shell/useWorkspaces.d.ts.map +1 -0
- package/types/shell/workspaceIcons.d.ts +9 -0
- package/types/shell/workspaceIcons.d.ts.map +1 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoffice route paths.
|
|
3
|
+
*
|
|
4
|
+
* Route map (relative to the mount `basePath`, default "/backoffice"):
|
|
5
|
+
* {base} → home (default workspace)
|
|
6
|
+
* {base}/[slug] → workspace page OR doctype list (runtime-resolved)
|
|
7
|
+
* {base}/[slug]/view/[view] → alternate doctype views (report, kanban, …)
|
|
8
|
+
* {base}/[slug]/new → new document (optional `?d=` JSON prefill)
|
|
9
|
+
* {base}/[slug]/[name] → document form page
|
|
10
|
+
*
|
|
11
|
+
* Slugs follow frappe's router slugs: lowercase, spaces → dashes
|
|
12
|
+
* ("Sales Order" → "sales-order").
|
|
13
|
+
*
|
|
14
|
+
* Surfaces inside the package MUST build paths through
|
|
15
|
+
* `useBackofficeConfig().paths` (basePath-aware). The default-bound helpers
|
|
16
|
+
* at the bottom exist for host apps mounted at the canonical "/backoffice"
|
|
17
|
+
* prefix — their template-literal return types match one-router's generated
|
|
18
|
+
* typed-route unions so they can be passed straight to router.push and
|
|
19
|
+
* <Link href>.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export const BACKOFFICE_BASE = "/backoffice";
|
|
23
|
+
|
|
24
|
+
export type BackofficeSubPath = `${typeof BACKOFFICE_BASE}/${string}`;
|
|
25
|
+
export type BackofficePath = typeof BACKOFFICE_BASE | BackofficeSubPath;
|
|
26
|
+
|
|
27
|
+
export const BACKOFFICE_VIEWS = [
|
|
28
|
+
"list",
|
|
29
|
+
"report",
|
|
30
|
+
"kanban",
|
|
31
|
+
"calendar",
|
|
32
|
+
"tree",
|
|
33
|
+
"image",
|
|
34
|
+
"dashboard",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type BackofficeView = (typeof BACKOFFICE_VIEWS)[number];
|
|
38
|
+
|
|
39
|
+
export function isBackofficeView(value: string): value is BackofficeView {
|
|
40
|
+
return (BACKOFFICE_VIEWS as readonly string[]).includes(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** frappe.router.slug: "Sales Order" → "sales-order" */
|
|
44
|
+
export function toSlug(name: string): string {
|
|
45
|
+
return name.toLowerCase().replace(/ /g, "-");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Best-effort display name from a slug: "sales-order" → "Sales Order" */
|
|
49
|
+
export function slugToDisplayName(slug: string): string {
|
|
50
|
+
return slug.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parse the `?d=` new-doc defaults query (urlencoded JSON object). The
|
|
55
|
+
* router usually decodes the param already, so the raw value is tried first.
|
|
56
|
+
* Malformed or non-object input degrades to no defaults.
|
|
57
|
+
*/
|
|
58
|
+
export function parseDocDefaults(raw: string | undefined): Record<string, unknown> | undefined {
|
|
59
|
+
if (!raw) return undefined;
|
|
60
|
+
const candidates = [raw];
|
|
61
|
+
try {
|
|
62
|
+
const decoded = decodeURIComponent(raw);
|
|
63
|
+
if (decoded !== raw) candidates.push(decoded);
|
|
64
|
+
} catch {
|
|
65
|
+
// raw is not percent-encoded — the direct candidate covers it
|
|
66
|
+
}
|
|
67
|
+
for (const candidate of candidates) {
|
|
68
|
+
try {
|
|
69
|
+
const parsed: unknown = JSON.parse(candidate);
|
|
70
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
71
|
+
return parsed as Record<string, unknown>;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// not JSON in this shape — try the next candidate
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Path builders bound to a mount prefix. */
|
|
81
|
+
export interface BackofficePaths {
|
|
82
|
+
/** The mount prefix these builders are bound to (no trailing slash). */
|
|
83
|
+
base: string;
|
|
84
|
+
home(): string;
|
|
85
|
+
workspace(workspaceName: string): string;
|
|
86
|
+
list(doctype: string): string;
|
|
87
|
+
view(doctype: string, view: BackofficeView): string;
|
|
88
|
+
/**
|
|
89
|
+
* New-document route. Optional `defaults` become the create form's initial
|
|
90
|
+
* field values, carried as `?d=<urlencoded JSON object>` — desk parity for
|
|
91
|
+
* creating from context (kanban column "+", calendar day click, …).
|
|
92
|
+
*/
|
|
93
|
+
newDoc(doctype: string, defaults?: Record<string, unknown>): string;
|
|
94
|
+
form(doctype: string, name: string): string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function createBackofficePaths(basePath: string = BACKOFFICE_BASE): BackofficePaths {
|
|
98
|
+
const base = basePath.replace(/\/+$/, "") || "/";
|
|
99
|
+
const prefix = base === "/" ? "" : base;
|
|
100
|
+
return {
|
|
101
|
+
base,
|
|
102
|
+
home: () => base,
|
|
103
|
+
workspace: (workspaceName) => `${prefix}/${toSlug(workspaceName)}`,
|
|
104
|
+
list: (doctype) => `${prefix}/${toSlug(doctype)}`,
|
|
105
|
+
view: (doctype, view) =>
|
|
106
|
+
view === "list"
|
|
107
|
+
? `${prefix}/${toSlug(doctype)}`
|
|
108
|
+
: `${prefix}/${toSlug(doctype)}/view/${view}`,
|
|
109
|
+
newDoc: (doctype, defaults) => {
|
|
110
|
+
const path = `${prefix}/${toSlug(doctype)}/new`;
|
|
111
|
+
if (!defaults || Object.keys(defaults).length === 0) return path;
|
|
112
|
+
return `${path}?d=${encodeURIComponent(JSON.stringify(defaults))}`;
|
|
113
|
+
},
|
|
114
|
+
form: (doctype, name) => `${prefix}/${toSlug(doctype)}/${encodeURIComponent(name)}`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Default-bound helpers ("/backoffice" prefix — one-router typed-route compat)
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
const defaultPaths = createBackofficePaths(BACKOFFICE_BASE);
|
|
123
|
+
|
|
124
|
+
export function homePath(): BackofficePath {
|
|
125
|
+
return defaultPaths.home() as BackofficePath;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function workspacePath(workspaceName: string): BackofficeSubPath {
|
|
129
|
+
return defaultPaths.workspace(workspaceName) as BackofficeSubPath;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function listPath(doctype: string): BackofficeSubPath {
|
|
133
|
+
return defaultPaths.list(doctype) as BackofficeSubPath;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function viewPath(doctype: string, view: BackofficeView): BackofficeSubPath {
|
|
137
|
+
return defaultPaths.view(doctype, view) as BackofficeSubPath;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function newDocPath(doctype: string, defaults?: Record<string, unknown>): BackofficeSubPath {
|
|
141
|
+
return defaultPaths.newDoc(doctype, defaults) as BackofficeSubPath;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function formPath(doctype: string, name: string): BackofficeSubPath {
|
|
145
|
+
return defaultPaths.form(doctype, name) as BackofficeSubPath;
|
|
146
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-router adapter — subpath export `@multiplatform.one/backoffice/one-adapter`.
|
|
3
|
+
*
|
|
4
|
+
* Lives on its own export path so the MAIN entry stays router-free: `one` is
|
|
5
|
+
* an optional peer, only resolved by hosts that import this adapter (same
|
|
6
|
+
* pattern as `@multiplatform.one/router`'s `./seam` subpath).
|
|
7
|
+
*
|
|
8
|
+
* Usage (a One app's backoffice layout):
|
|
9
|
+
*
|
|
10
|
+
* const navigation = useOneNavigator();
|
|
11
|
+
* return (
|
|
12
|
+
* <BackofficeProvider frappe={{ baseURL }} navigation={navigation}>
|
|
13
|
+
* <BackofficeShell><Slot /></BackofficeShell>
|
|
14
|
+
* </BackofficeProvider>
|
|
15
|
+
* );
|
|
16
|
+
*/
|
|
17
|
+
import { useLocalSearchParams, usePathname, useRouter } from "one";
|
|
18
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
19
|
+
import {
|
|
20
|
+
ControlledNavigator,
|
|
21
|
+
type BackofficeNavigator,
|
|
22
|
+
type BackofficeParams,
|
|
23
|
+
} from "../navigation/navigator";
|
|
24
|
+
|
|
25
|
+
// SSR-safe layout effect: One renders routes server-side, where
|
|
26
|
+
// useLayoutEffect warns; the location mirror runs post-render either way.
|
|
27
|
+
const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A {@link BackofficeNavigator} backed by One's router. Referentially stable
|
|
31
|
+
* across renders; the current pathname + search params are mirrored into the
|
|
32
|
+
* navigator's subscribable location after every route change.
|
|
33
|
+
*/
|
|
34
|
+
export function useOneNavigator(): BackofficeNavigator {
|
|
35
|
+
const router = useRouter();
|
|
36
|
+
const pathname = usePathname();
|
|
37
|
+
const params = useLocalSearchParams() as BackofficeParams;
|
|
38
|
+
|
|
39
|
+
// One's router object is referentially stable, but route through a ref so
|
|
40
|
+
// even a host swapping router implementations stays wired.
|
|
41
|
+
const routerRef = useRef(router);
|
|
42
|
+
routerRef.current = router;
|
|
43
|
+
|
|
44
|
+
const [navigator] = useState(
|
|
45
|
+
() =>
|
|
46
|
+
new ControlledNavigator(
|
|
47
|
+
{
|
|
48
|
+
navigate: (path) => routerRef.current.push(path as never),
|
|
49
|
+
replace: (path) => routerRef.current.replace(path as never),
|
|
50
|
+
back: () => routerRef.current.back(),
|
|
51
|
+
},
|
|
52
|
+
{ path: pathname, params },
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
useIsomorphicLayoutEffect(() => {
|
|
57
|
+
navigator.setLocation({ path: pathname, params });
|
|
58
|
+
}, [navigator, pathname, params]);
|
|
59
|
+
|
|
60
|
+
return navigator;
|
|
61
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { FrappeApp, type AuthConfig } from "@multiplatform.one/frappe";
|
|
2
|
+
import { useFrappeConfig } from "@multiplatform.one/frappe-ui";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
|
|
5
|
+
const appCache = new Map<string, FrappeApp>();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Memoized FrappeApp built from the ambient FrappeProvider config (mounted
|
|
9
|
+
* by BackofficeProvider). Use `app.call()` for desk RPCs, `app.db()` for
|
|
10
|
+
* CRUD, `app.file()` for uploads. Prefer Frappe* components /
|
|
11
|
+
* useFrappeCollection where possible — reach for this only when no component
|
|
12
|
+
* covers the API. Returns undefined outside a provider.
|
|
13
|
+
*/
|
|
14
|
+
export function useFrappeApp(): FrappeApp | undefined {
|
|
15
|
+
const config = useFrappeConfig();
|
|
16
|
+
const baseURL = config?.baseURL;
|
|
17
|
+
// Without socketPort the realtime module dials `${baseURL}/socket.io`
|
|
18
|
+
// (:8000 in dev) instead of frappe's socketio server (:9000), producing a
|
|
19
|
+
// CORS-failed handshake on every mount.
|
|
20
|
+
const socketPort = config?.socketPort;
|
|
21
|
+
const useToken = config?.auth?.useToken;
|
|
22
|
+
const token = config?.auth?.token;
|
|
23
|
+
const type = config?.auth?.type;
|
|
24
|
+
return useMemo(() => {
|
|
25
|
+
if (!baseURL) return undefined;
|
|
26
|
+
const key = `${baseURL}|${socketPort ?? ""}|${useToken ? "t" : ""}|${token ?? ""}|${type ?? ""}`;
|
|
27
|
+
let app = appCache.get(key);
|
|
28
|
+
if (!app) {
|
|
29
|
+
app = new FrappeApp(baseURL, {
|
|
30
|
+
useToken,
|
|
31
|
+
token,
|
|
32
|
+
type: (type === "Bearer" ? "Bearer" : type ? "token" : undefined) as AuthConfig["type"],
|
|
33
|
+
realtimeOptions: socketPort ? { socketPort } : undefined,
|
|
34
|
+
});
|
|
35
|
+
appCache.set(key, app);
|
|
36
|
+
}
|
|
37
|
+
return app;
|
|
38
|
+
}, [baseURL, socketPort, useToken, token, type]);
|
|
39
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoffice desk chrome: top navbar (app title → home, centered awesomebar,
|
|
3
|
+
* notifications / help / user menus) and the left workspace sidebar around
|
|
4
|
+
* the routed content.
|
|
5
|
+
*
|
|
6
|
+
* Router-free by design — navigation and the active path come from the
|
|
7
|
+
* BackofficeProvider's navigator (explicit `activePath`/`onNavigate` props
|
|
8
|
+
* override it for stories/tests). Capability flags from the provider gate
|
|
9
|
+
* every piece of chrome; `renderShellHeader`/`renderSidebarFooter` slots
|
|
10
|
+
* replace/extend the built-ins. Narrow viewports collapse the sidebar into
|
|
11
|
+
* an overlay drawer (same breakpoint as frappe-ui's DeskShell:
|
|
12
|
+
* DESK_NARROW_BREAKPOINT === theme NARROW_BREAKPOINT).
|
|
13
|
+
*/
|
|
14
|
+
import { Button, SizableText, XStack, YStack, isWeb } from "@multiplatform.one/components";
|
|
15
|
+
import { useLayoutSizeClass, useResolvedKnobs } from "@multiplatform.one/theme";
|
|
16
|
+
import { ListIcon, XIcon } from "@phosphor-icons/react";
|
|
17
|
+
import type React from "react";
|
|
18
|
+
import { useEffect, useRef, useState } from "react";
|
|
19
|
+
import { useTranslation } from "react-i18next";
|
|
20
|
+
import {
|
|
21
|
+
BackofficeAwesomebar,
|
|
22
|
+
type BackofficeAwesomebarHandle,
|
|
23
|
+
} from "../chrome/BackofficeAwesomebar";
|
|
24
|
+
import { HelpMenu } from "../chrome/HelpMenu";
|
|
25
|
+
import { NotificationsButton } from "../chrome/NotificationsButton";
|
|
26
|
+
import { useBackofficeShortcuts } from "../chrome/shortcuts";
|
|
27
|
+
import { UserMenu } from "../chrome/UserMenu";
|
|
28
|
+
import {
|
|
29
|
+
useBackofficeCapabilities,
|
|
30
|
+
useBackofficeLocation,
|
|
31
|
+
useBackofficeNavigator,
|
|
32
|
+
useBackofficePaths,
|
|
33
|
+
useBackofficeSlots,
|
|
34
|
+
} from "../config/BackofficeProvider";
|
|
35
|
+
import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
|
|
36
|
+
import { WorkspaceSidebar } from "./WorkspaceSidebar";
|
|
37
|
+
|
|
38
|
+
export interface BackofficeShellProps {
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
/** Current path for the sidebar active state (default: navigator location). */
|
|
41
|
+
activePath?: string;
|
|
42
|
+
/** Navigation handler (default: navigator push). */
|
|
43
|
+
onNavigate?: (path: string) => void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Cross-platform narrow-viewport detection: theme `compact` size class =
|
|
48
|
+
* width < NARROW_BREAKPOINT (640) — matchMedia on web, window dimensions on
|
|
49
|
+
* native, so phones get the drawer instead of a permanent desktop rail.
|
|
50
|
+
*/
|
|
51
|
+
function useIsNarrow(): boolean {
|
|
52
|
+
return useLayoutSizeClass() === "compact";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function BackofficeShell({ children, activePath, onNavigate }: BackofficeShellProps) {
|
|
56
|
+
const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
|
|
57
|
+
const { knobProps } = useResolvedKnobs();
|
|
58
|
+
const capabilities = useBackofficeCapabilities();
|
|
59
|
+
const slots = useBackofficeSlots();
|
|
60
|
+
const navigator = useBackofficeNavigator();
|
|
61
|
+
const location = useBackofficeLocation();
|
|
62
|
+
const paths = useBackofficePaths();
|
|
63
|
+
const isNarrow = useIsNarrow();
|
|
64
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
65
|
+
|
|
66
|
+
const resolvedActivePath = activePath ?? location.path;
|
|
67
|
+
const navigate = onNavigate ?? navigator.navigate;
|
|
68
|
+
|
|
69
|
+
const sidebarEnabled = capabilities.sidebar.enabled;
|
|
70
|
+
|
|
71
|
+
// Global desk shortcuts (Mod+K / Mod+G → awesomebar). One document
|
|
72
|
+
// listener for the whole chrome; SSR/native-safe, skips editable targets.
|
|
73
|
+
const awesomebarRef = useRef<BackofficeAwesomebarHandle>(null);
|
|
74
|
+
useBackofficeShortcuts({
|
|
75
|
+
onFocusSearch: capabilities.awesomebar.enabled
|
|
76
|
+
? () => awesomebarRef.current?.focus()
|
|
77
|
+
: undefined,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Leaving the narrow range always closes the drawer.
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!isNarrow) setDrawerOpen(false);
|
|
83
|
+
}, [isNarrow]);
|
|
84
|
+
|
|
85
|
+
// Escape dismisses the drawer (web-only keyboard listener).
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!isWeb || typeof document === "undefined" || !drawerOpen) return;
|
|
88
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
89
|
+
if (event.key === "Escape") setDrawerOpen(false);
|
|
90
|
+
};
|
|
91
|
+
document.addEventListener("keydown", onKeyDown);
|
|
92
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
93
|
+
}, [drawerOpen]);
|
|
94
|
+
|
|
95
|
+
const handleNavigate = (path: string) => {
|
|
96
|
+
if (isNarrow) setDrawerOpen(false);
|
|
97
|
+
navigate(path);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const surfaceBorderWidth = knobProps.surface.borderWidth;
|
|
101
|
+
|
|
102
|
+
const sidebarContent = (
|
|
103
|
+
<>
|
|
104
|
+
<WorkspaceSidebar activePath={resolvedActivePath} onNavigate={handleNavigate} />
|
|
105
|
+
{slots.renderSidebarFooter?.()}
|
|
106
|
+
</>
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const headerContent = (
|
|
110
|
+
<>
|
|
111
|
+
{isNarrow && sidebarEnabled && (
|
|
112
|
+
<Button
|
|
113
|
+
chromeless
|
|
114
|
+
circular
|
|
115
|
+
size="$3"
|
|
116
|
+
icon={drawerOpen ? XIcon : ListIcon}
|
|
117
|
+
aria-label={t("shell.toggleSidebar", "Toggle sidebar")}
|
|
118
|
+
aria-expanded={drawerOpen}
|
|
119
|
+
onPress={() => setDrawerOpen((open) => !open)}
|
|
120
|
+
data-testid="backoffice-sidebar-toggle"
|
|
121
|
+
/>
|
|
122
|
+
)}
|
|
123
|
+
<Button
|
|
124
|
+
chromeless
|
|
125
|
+
size="$3"
|
|
126
|
+
paddingHorizontal="$2"
|
|
127
|
+
onPress={() => handleNavigate(paths.home())}
|
|
128
|
+
aria-label={t("shell.home", "Home")}
|
|
129
|
+
data-testid="backoffice-home"
|
|
130
|
+
>
|
|
131
|
+
<SizableText size="$5" fontWeight="700">
|
|
132
|
+
{t("shell.title", "Backoffice")}
|
|
133
|
+
</SizableText>
|
|
134
|
+
</Button>
|
|
135
|
+
|
|
136
|
+
{/* Centered awesomebar (the flex spacer keeps the right chrome pinned
|
|
137
|
+
when the awesomebar capability is off) */}
|
|
138
|
+
<XStack flex={1} minWidth={0} justifyContent="center">
|
|
139
|
+
{capabilities.awesomebar.enabled && (
|
|
140
|
+
<XStack flex={1} maxWidth={560} minWidth={0}>
|
|
141
|
+
<BackofficeAwesomebar focusRef={awesomebarRef} />
|
|
142
|
+
</XStack>
|
|
143
|
+
)}
|
|
144
|
+
</XStack>
|
|
145
|
+
|
|
146
|
+
{/* Right chrome */}
|
|
147
|
+
<XStack alignItems="center" gap="$1" flexShrink={0}>
|
|
148
|
+
{capabilities.notifications.enabled && <NotificationsButton />}
|
|
149
|
+
{capabilities.help.enabled && <HelpMenu />}
|
|
150
|
+
{capabilities.userMenu.enabled && <UserMenu />}
|
|
151
|
+
</XStack>
|
|
152
|
+
</>
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<YStack flex={1} height="100%" width="100%" overflow="hidden" data-testid="backoffice-shell">
|
|
157
|
+
{/* Top navbar */}
|
|
158
|
+
<XStack
|
|
159
|
+
role="banner"
|
|
160
|
+
{...knobProps.surface}
|
|
161
|
+
// Surface knobs paint a full box border; keep only the bottom edge
|
|
162
|
+
// (DeskShell precedent, SB-M-1708).
|
|
163
|
+
borderWidth={0}
|
|
164
|
+
borderBottomWidth={surfaceBorderWidth}
|
|
165
|
+
borderBottomColor={knobProps.surface.borderColor}
|
|
166
|
+
alignItems="center"
|
|
167
|
+
paddingHorizontal="$3"
|
|
168
|
+
paddingVertical="$2"
|
|
169
|
+
gap="$2"
|
|
170
|
+
flexShrink={0}
|
|
171
|
+
>
|
|
172
|
+
{slots.renderShellHeader
|
|
173
|
+
? slots.renderShellHeader({ defaultContent: headerContent })
|
|
174
|
+
: headerContent}
|
|
175
|
+
</XStack>
|
|
176
|
+
|
|
177
|
+
<XStack flex={1} minWidth={0} position="relative" overflow="hidden">
|
|
178
|
+
{/* Desktop rail — in flow */}
|
|
179
|
+
{sidebarEnabled && !isNarrow && (
|
|
180
|
+
<YStack role="navigation" flexShrink={0} data-testid="backoffice-sidebar-rail">
|
|
181
|
+
{sidebarContent}
|
|
182
|
+
</YStack>
|
|
183
|
+
)}
|
|
184
|
+
|
|
185
|
+
{/* Narrow drawer + scrim */}
|
|
186
|
+
{sidebarEnabled && isNarrow && drawerOpen && (
|
|
187
|
+
<>
|
|
188
|
+
<YStack
|
|
189
|
+
position="absolute"
|
|
190
|
+
top={0}
|
|
191
|
+
left={0}
|
|
192
|
+
right={0}
|
|
193
|
+
bottom={0}
|
|
194
|
+
backgroundColor="$shadowColor"
|
|
195
|
+
opacity={0.5}
|
|
196
|
+
zIndex={10}
|
|
197
|
+
onPress={() => setDrawerOpen(false)}
|
|
198
|
+
data-testid="backoffice-sidebar-scrim"
|
|
199
|
+
/>
|
|
200
|
+
<YStack
|
|
201
|
+
role="navigation"
|
|
202
|
+
position="absolute"
|
|
203
|
+
top={0}
|
|
204
|
+
left={0}
|
|
205
|
+
bottom={0}
|
|
206
|
+
zIndex={11}
|
|
207
|
+
backgroundColor="$background"
|
|
208
|
+
data-testid="backoffice-sidebar-drawer"
|
|
209
|
+
>
|
|
210
|
+
{sidebarContent}
|
|
211
|
+
</YStack>
|
|
212
|
+
</>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
{/* Routed content — pages own their own headers/breadcrumbs */}
|
|
216
|
+
<YStack role="main" flex={1} minWidth={0}>
|
|
217
|
+
{children}
|
|
218
|
+
</YStack>
|
|
219
|
+
</XStack>
|
|
220
|
+
</YStack>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Left workspace navigation for the backoffice shell (desk parity).
|
|
3
|
+
*
|
|
4
|
+
* Private workspaces (for_user = session user) on top, public workspaces
|
|
5
|
+
* below ordered by sequence_id, children nested via parent_page (rendered
|
|
6
|
+
* indented under their parent). Data is live via useWorkspaces; paths come
|
|
7
|
+
* from the BackofficeProvider (basePath-aware).
|
|
8
|
+
*/
|
|
9
|
+
import {
|
|
10
|
+
Sidebar,
|
|
11
|
+
Spinner,
|
|
12
|
+
XStack,
|
|
13
|
+
YStack,
|
|
14
|
+
type SidebarItem,
|
|
15
|
+
type SidebarSection,
|
|
16
|
+
} from "@multiplatform.one/components";
|
|
17
|
+
import { useMemo } from "react";
|
|
18
|
+
import { useTranslation } from "react-i18next";
|
|
19
|
+
import { useBackofficePaths } from "../config/BackofficeProvider";
|
|
20
|
+
import { BACKOFFICE_I18N_NAMESPACE } from "../i18n";
|
|
21
|
+
import type { BackofficePaths } from "../navigation/paths";
|
|
22
|
+
import { useWorkspaces, type WorkspaceDoc } from "./useWorkspaces";
|
|
23
|
+
import { workspaceIcon } from "./workspaceIcons";
|
|
24
|
+
|
|
25
|
+
export const WORKSPACE_SIDEBAR_WIDTH = 250;
|
|
26
|
+
|
|
27
|
+
export interface WorkspaceSidebarProps {
|
|
28
|
+
/** Current path, used to highlight the active workspace. */
|
|
29
|
+
activePath?: string;
|
|
30
|
+
/** Called with the target path when a workspace is selected. */
|
|
31
|
+
onNavigate?: (path: string) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function workspaceItem(
|
|
35
|
+
workspace: WorkspaceDoc,
|
|
36
|
+
depth: number,
|
|
37
|
+
paths: BackofficePaths,
|
|
38
|
+
activePath: string | undefined,
|
|
39
|
+
onNavigate: ((path: string) => void) | undefined,
|
|
40
|
+
): SidebarItem {
|
|
41
|
+
const path = paths.workspace(workspace.name);
|
|
42
|
+
const IconComponent = workspaceIcon(workspace.icon);
|
|
43
|
+
const icon = (
|
|
44
|
+
// Depth-based inset carried by the icon slot — the Sidebar row API has
|
|
45
|
+
// no nesting support, so children indent icon+label via this wrapper.
|
|
46
|
+
<XStack paddingLeft={depth > 0 ? depth * 16 : 0}>
|
|
47
|
+
<IconComponent size={16} />
|
|
48
|
+
</XStack>
|
|
49
|
+
);
|
|
50
|
+
return {
|
|
51
|
+
label: workspace.title || workspace.name,
|
|
52
|
+
value: path,
|
|
53
|
+
icon,
|
|
54
|
+
active: activePath === path,
|
|
55
|
+
onPress: onNavigate ? () => onNavigate(path) : undefined,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Flatten a workspace tree into indented sidebar items (children follow parents). */
|
|
60
|
+
function flattenTree(
|
|
61
|
+
roots: WorkspaceDoc[],
|
|
62
|
+
childrenByParent: Map<string, WorkspaceDoc[]>,
|
|
63
|
+
paths: BackofficePaths,
|
|
64
|
+
activePath: string | undefined,
|
|
65
|
+
onNavigate: ((path: string) => void) | undefined,
|
|
66
|
+
depth = 0,
|
|
67
|
+
): SidebarItem[] {
|
|
68
|
+
const items: SidebarItem[] = [];
|
|
69
|
+
for (const workspace of roots) {
|
|
70
|
+
items.push(workspaceItem(workspace, depth, paths, activePath, onNavigate));
|
|
71
|
+
const children = childrenByParent.get(workspace.name);
|
|
72
|
+
if (children?.length) {
|
|
73
|
+
items.push(
|
|
74
|
+
...flattenTree(children, childrenByParent, paths, activePath, onNavigate, depth + 1),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return items;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function WorkspaceSidebar({ activePath, onNavigate }: WorkspaceSidebarProps) {
|
|
82
|
+
const { t } = useTranslation(BACKOFFICE_I18N_NAMESPACE);
|
|
83
|
+
const paths = useBackofficePaths();
|
|
84
|
+
const { privateWorkspaces, publicRoots, childrenByParent, isLoading } = useWorkspaces();
|
|
85
|
+
|
|
86
|
+
const sections = useMemo<SidebarSection[]>(() => {
|
|
87
|
+
const result: SidebarSection[] = [];
|
|
88
|
+
if (privateWorkspaces.length > 0) {
|
|
89
|
+
result.push({
|
|
90
|
+
title: t("sidebar.private", "Private"),
|
|
91
|
+
items: privateWorkspaces.map((workspace) =>
|
|
92
|
+
workspaceItem(workspace, 0, paths, activePath, onNavigate),
|
|
93
|
+
),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (publicRoots.length > 0) {
|
|
97
|
+
result.push({
|
|
98
|
+
title: t("sidebar.public", "Public"),
|
|
99
|
+
items: flattenTree(publicRoots, childrenByParent, paths, activePath, onNavigate),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}, [privateWorkspaces, publicRoots, childrenByParent, paths, activePath, onNavigate, t]);
|
|
104
|
+
|
|
105
|
+
if (isLoading && sections.length === 0) {
|
|
106
|
+
return (
|
|
107
|
+
<YStack
|
|
108
|
+
width={WORKSPACE_SIDEBAR_WIDTH}
|
|
109
|
+
alignItems="center"
|
|
110
|
+
paddingTop="$6"
|
|
111
|
+
aria-label={t("sidebar.loading", "Loading workspaces")}
|
|
112
|
+
>
|
|
113
|
+
<Spinner size="small" />
|
|
114
|
+
</YStack>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return <Sidebar sections={sections} width={WORKSPACE_SIDEBAR_WIDTH} />;
|
|
119
|
+
}
|