@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,126 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
3
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
4
|
+
import { fireEvent, screen } from "@testing-library/react";
|
|
5
|
+
import { describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { createMemoryNavigator } from "../navigation/navigator";
|
|
7
|
+
import { BackofficeShell } from "../shell/BackofficeShell";
|
|
8
|
+
import { BackofficeProvider, type BackofficeProviderProps } from "./BackofficeProvider";
|
|
9
|
+
|
|
10
|
+
const MOCK_HOST = "https://backoffice-package.mock.test";
|
|
11
|
+
|
|
12
|
+
const makeFixtures = () =>
|
|
13
|
+
new InMemoryFixtureProvider({
|
|
14
|
+
Workspace: [
|
|
15
|
+
{
|
|
16
|
+
name: "Tools",
|
|
17
|
+
doctype: "Workspace",
|
|
18
|
+
title: "Tools",
|
|
19
|
+
icon: "tool",
|
|
20
|
+
parent_page: "",
|
|
21
|
+
public: 1,
|
|
22
|
+
for_user: "",
|
|
23
|
+
sequence_id: 1,
|
|
24
|
+
module: "Automation",
|
|
25
|
+
is_hidden: 0,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
DocType: [{ name: "ToDo", doctype: "DocType" }],
|
|
29
|
+
"Notification Log": [],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
function renderShell(props: Partial<BackofficeProviderProps> = {}) {
|
|
33
|
+
const navigation = props.navigation ?? createMemoryNavigator("/backoffice");
|
|
34
|
+
return {
|
|
35
|
+
navigation,
|
|
36
|
+
...renderWithProviders(
|
|
37
|
+
<BackofficeProvider
|
|
38
|
+
frappe={{ baseURL: MOCK_HOST, fixtures: makeFixtures() }}
|
|
39
|
+
navigation={navigation}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
<BackofficeShell>
|
|
43
|
+
<div>page body</div>
|
|
44
|
+
</BackofficeShell>
|
|
45
|
+
</BackofficeProvider>,
|
|
46
|
+
),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("BackofficeProvider capability flags", () => {
|
|
51
|
+
it("renders the full chrome by default", () => {
|
|
52
|
+
const { container } = renderShell();
|
|
53
|
+
|
|
54
|
+
expect(screen.getByTestId("backoffice-shell")).toBeTruthy();
|
|
55
|
+
expect(screen.getByTestId("backoffice-awesomebar")).toBeTruthy();
|
|
56
|
+
expect(screen.getByTestId("backoffice-notifications-button")).toBeTruthy();
|
|
57
|
+
expect(screen.getByTestId("backoffice-help-trigger")).toBeTruthy();
|
|
58
|
+
expect(container.querySelector('[aria-label="User menu"]')).toBeTruthy();
|
|
59
|
+
expect(screen.getByTestId("backoffice-sidebar-rail")).toBeTruthy();
|
|
60
|
+
expect(screen.getByText("page body")).toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("boolean flags gate each piece of chrome", () => {
|
|
64
|
+
const { container } = renderShell({
|
|
65
|
+
capabilities: {
|
|
66
|
+
awesomebar: false,
|
|
67
|
+
notifications: false,
|
|
68
|
+
userMenu: false,
|
|
69
|
+
help: false,
|
|
70
|
+
sidebar: false,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(screen.queryByTestId("backoffice-awesomebar")).toBeNull();
|
|
75
|
+
expect(screen.queryByTestId("backoffice-notifications-button")).toBeNull();
|
|
76
|
+
expect(screen.queryByTestId("backoffice-help-trigger")).toBeNull();
|
|
77
|
+
expect(container.querySelector('[aria-label="User menu"]')).toBeNull();
|
|
78
|
+
expect(screen.queryByTestId("backoffice-sidebar-rail")).toBeNull();
|
|
79
|
+
// Content always renders — flags remove chrome, not the page.
|
|
80
|
+
expect(screen.getByText("page body")).toBeTruthy();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("object flags resolve enabled + per-feature config", () => {
|
|
84
|
+
renderShell({
|
|
85
|
+
capabilities: { notifications: { enabled: false }, awesomebar: { enabled: true } },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(screen.queryByTestId("backoffice-notifications-button")).toBeNull();
|
|
89
|
+
expect(screen.getByTestId("backoffice-awesomebar")).toBeTruthy();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("renders host slots (sidebar footer)", () => {
|
|
93
|
+
renderShell({
|
|
94
|
+
slots: { renderSidebarFooter: () => <div data-testid="host-sidebar-footer">custom</div> },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(screen.getByTestId("host-sidebar-footer")).toBeTruthy();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("BackofficeProvider navigation", () => {
|
|
102
|
+
it("shell home button navigates through the adapter and emits an event", () => {
|
|
103
|
+
const onEvent = vi.fn();
|
|
104
|
+
const { navigation } = renderShell({ onEvent });
|
|
105
|
+
|
|
106
|
+
fireEvent.click(screen.getByTestId("backoffice-home"));
|
|
107
|
+
|
|
108
|
+
expect(navigation.getLocation().path).toBe("/backoffice");
|
|
109
|
+
expect(onEvent).toHaveBeenCalledWith({
|
|
110
|
+
type: "navigate",
|
|
111
|
+
path: "/backoffice",
|
|
112
|
+
mode: "push",
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("basePath rebinds every path the chrome navigates to", () => {
|
|
117
|
+
const onEvent = vi.fn();
|
|
118
|
+
const navigation = createMemoryNavigator("/admin");
|
|
119
|
+
renderShell({ navigation, basePath: "/admin", onEvent });
|
|
120
|
+
|
|
121
|
+
fireEvent.click(screen.getByTestId("backoffice-home"));
|
|
122
|
+
|
|
123
|
+
expect(onEvent).toHaveBeenCalledWith({ type: "navigate", path: "/admin", mode: "push" });
|
|
124
|
+
expect(navigation.getLocation().path).toBe("/admin");
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BackofficeProvider — the single configuration surface for embedding the
|
|
3
|
+
* backoffice in a host app.
|
|
4
|
+
*
|
|
5
|
+
* It composes @multiplatform.one/frappe-ui's FrappeProvider internally (the
|
|
6
|
+
* `frappe` prop), publishes the navigation seam + capability flags + slots +
|
|
7
|
+
* event bus through BackofficeConfigContext (consumed by every backoffice
|
|
8
|
+
* surface), registers the package's "backoffice" i18n namespace, and applies
|
|
9
|
+
* host field-registry overrides.
|
|
10
|
+
*
|
|
11
|
+
* Surfaces render without a provider too (stories/tests): the context
|
|
12
|
+
* default is a fully-enabled config with an inert navigator.
|
|
13
|
+
*/
|
|
14
|
+
import {
|
|
15
|
+
FrappeProvider,
|
|
16
|
+
registerField,
|
|
17
|
+
type FieldRenderProps,
|
|
18
|
+
type FrappeProviderProps,
|
|
19
|
+
} from "@multiplatform.one/frappe-ui";
|
|
20
|
+
import type { i18n as I18nInstance } from "i18next";
|
|
21
|
+
import type { ComponentType, ReactNode } from "react";
|
|
22
|
+
import React, { createContext, useContext, useMemo, useRef, useState } from "react";
|
|
23
|
+
import { useSyncExternalStore } from "react";
|
|
24
|
+
import { registerBackofficeTranslations } from "../i18n";
|
|
25
|
+
import {
|
|
26
|
+
createNoopNavigator,
|
|
27
|
+
type BackofficeLocation,
|
|
28
|
+
type BackofficeNavigator,
|
|
29
|
+
} from "../navigation/navigator";
|
|
30
|
+
import { BACKOFFICE_BASE, createBackofficePaths, type BackofficePaths } from "../navigation/paths";
|
|
31
|
+
import {
|
|
32
|
+
isDoctypeAllowed,
|
|
33
|
+
resolveCapabilities,
|
|
34
|
+
type BackofficeCapabilities,
|
|
35
|
+
type BackofficeDoctypeScope,
|
|
36
|
+
type ResolvedBackofficeCapabilities,
|
|
37
|
+
} from "./capabilities";
|
|
38
|
+
import type { BackofficeEvent, BackofficeEventHandler } from "./events";
|
|
39
|
+
import type { BackofficeSlots } from "./slots";
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Types
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
/** Frappe connection config — fed into frappe-ui's FrappeProvider. */
|
|
46
|
+
export interface BackofficeFrappeConfig {
|
|
47
|
+
/** Base URL of the Frappe server, e.g. "https://mysite.frappe.cloud". */
|
|
48
|
+
baseURL: string;
|
|
49
|
+
/** Override port for the Socket.IO realtime connection (e.g. 9000 in dev). */
|
|
50
|
+
socketPort?: number;
|
|
51
|
+
/** Authentication configuration (token auth for cross-origin/native hosts). */
|
|
52
|
+
auth?: FrappeProviderProps["auth"];
|
|
53
|
+
/** Sync options for the live data engine (persistKey, cdcInterval, …). */
|
|
54
|
+
syncOptions?: FrappeProviderProps["syncOptions"];
|
|
55
|
+
/** Extra Socket.IO client options for the realtime connection. */
|
|
56
|
+
socketOptions?: FrappeProviderProps["socketOptions"];
|
|
57
|
+
/** Fixture provider (stories/tests — no network). */
|
|
58
|
+
fixtures?: FrappeProviderProps["fixtures"];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Host color-scheme adapter (drives the user menu's "Toggle Theme"). */
|
|
62
|
+
export interface BackofficeAppearance {
|
|
63
|
+
/** Current scheme value. */
|
|
64
|
+
scheme: "light" | "dark" | "system" | (string & {});
|
|
65
|
+
/** Set the scheme. */
|
|
66
|
+
setScheme: (scheme: "light" | "dark" | "system") => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Host-injected custom action (form toolbars, list toolbars). */
|
|
70
|
+
export interface BackofficeActionContext {
|
|
71
|
+
doctype: string;
|
|
72
|
+
/** Document name (form actions; undefined for unsaved docs). */
|
|
73
|
+
name?: string;
|
|
74
|
+
/** Selected row names (list bulk actions). */
|
|
75
|
+
selection?: readonly string[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface BackofficeAction {
|
|
79
|
+
id: string;
|
|
80
|
+
label: string;
|
|
81
|
+
onPress: (context: BackofficeActionContext) => void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface BackofficeActions {
|
|
85
|
+
/** Extra actions on the document form toolbar. */
|
|
86
|
+
form?: readonly BackofficeAction[];
|
|
87
|
+
/** Extra actions on the list toolbar / bulk-actions bar. */
|
|
88
|
+
list?: readonly BackofficeAction[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface BackofficeProviderProps {
|
|
92
|
+
children: ReactNode;
|
|
93
|
+
/** Frappe connection — feeds FrappeProvider internally. */
|
|
94
|
+
frappe: BackofficeFrappeConfig;
|
|
95
|
+
/**
|
|
96
|
+
* Navigation adapter. Use `useOneNavigator()` from
|
|
97
|
+
* `@multiplatform.one/backoffice/one-adapter` in One apps,
|
|
98
|
+
* `createMemoryNavigator()` in tests/stories, or bridge your own router
|
|
99
|
+
* with `ControlledNavigator`.
|
|
100
|
+
*/
|
|
101
|
+
navigation: BackofficeNavigator;
|
|
102
|
+
/** URL prefix the backoffice is mounted under. Default "/backoffice". */
|
|
103
|
+
basePath?: string;
|
|
104
|
+
/** Feature visibility/behavior flags. Everything defaults ON. */
|
|
105
|
+
capabilities?: BackofficeCapabilities;
|
|
106
|
+
/** Restrict which doctypes are reachable (awesomebar, lists, links). */
|
|
107
|
+
doctypes?: BackofficeDoctypeScope;
|
|
108
|
+
/**
|
|
109
|
+
* Field-renderer overrides merged into frappe-ui's field registry
|
|
110
|
+
* (fieldtype → component), e.g. `{ Rating: MyRating }`.
|
|
111
|
+
*/
|
|
112
|
+
fields?: Record<string, ComponentType<FieldRenderProps>>;
|
|
113
|
+
/** Host-injected custom actions (form/list toolbars). */
|
|
114
|
+
actions?: BackofficeActions;
|
|
115
|
+
/** Render-prop slots replacing built-in chrome. */
|
|
116
|
+
slots?: BackofficeSlots;
|
|
117
|
+
/** Color-scheme adapter for the user menu's "Toggle Theme". */
|
|
118
|
+
appearance?: BackofficeAppearance;
|
|
119
|
+
/** Event bus — every notable backoffice action lands here. */
|
|
120
|
+
onEvent?: BackofficeEventHandler;
|
|
121
|
+
/**
|
|
122
|
+
* i18next instance to register the "backoffice" namespace on (defaults to
|
|
123
|
+
* the global singleton).
|
|
124
|
+
*/
|
|
125
|
+
i18nInstance?: I18nInstance;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Resolved config every backoffice surface consumes. */
|
|
129
|
+
export interface BackofficeConfig {
|
|
130
|
+
frappe?: BackofficeFrappeConfig;
|
|
131
|
+
navigation: BackofficeNavigator;
|
|
132
|
+
basePath: string;
|
|
133
|
+
paths: BackofficePaths;
|
|
134
|
+
capabilities: ResolvedBackofficeCapabilities;
|
|
135
|
+
doctypes?: BackofficeDoctypeScope;
|
|
136
|
+
actions: BackofficeActions;
|
|
137
|
+
slots: BackofficeSlots;
|
|
138
|
+
appearance?: BackofficeAppearance;
|
|
139
|
+
/** Emit an event to the host's `onEvent` bus (no-op when unset). */
|
|
140
|
+
emitEvent: (event: BackofficeEvent) => void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
// Context
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
|
|
147
|
+
const DEFAULT_CONFIG: BackofficeConfig = {
|
|
148
|
+
navigation: createNoopNavigator(BACKOFFICE_BASE),
|
|
149
|
+
basePath: BACKOFFICE_BASE,
|
|
150
|
+
paths: createBackofficePaths(BACKOFFICE_BASE),
|
|
151
|
+
capabilities: resolveCapabilities(),
|
|
152
|
+
actions: {},
|
|
153
|
+
slots: {},
|
|
154
|
+
emitEvent: () => {},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const BackofficeConfigContext = createContext<BackofficeConfig>(DEFAULT_CONFIG);
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* The resolved backoffice config. Outside a BackofficeProvider this returns
|
|
161
|
+
* a fully-enabled default config with an inert navigator, so surfaces stay
|
|
162
|
+
* mountable in isolation (stories, tests).
|
|
163
|
+
*/
|
|
164
|
+
export function useBackofficeConfig(): BackofficeConfig {
|
|
165
|
+
return useContext(BackofficeConfigContext);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function useBackofficeCapabilities(): ResolvedBackofficeCapabilities {
|
|
169
|
+
return useBackofficeConfig().capabilities;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function useBackofficeNavigator(): BackofficeNavigator {
|
|
173
|
+
return useBackofficeConfig().navigation;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function useBackofficePaths(): BackofficePaths {
|
|
177
|
+
return useBackofficeConfig().paths;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function useBackofficeSlots(): BackofficeSlots {
|
|
181
|
+
return useBackofficeConfig().slots;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Current location from the navigation adapter (subscription-backed). */
|
|
185
|
+
export function useBackofficeLocation(): BackofficeLocation {
|
|
186
|
+
const navigator = useBackofficeNavigator();
|
|
187
|
+
return useSyncExternalStore(navigator.subscribe, navigator.getLocation, navigator.getLocation);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Is `doctype` reachable under the provider's doctype scope? */
|
|
191
|
+
export function useIsDoctypeAllowed(): (doctype: string) => boolean {
|
|
192
|
+
const { doctypes } = useBackofficeConfig();
|
|
193
|
+
return useMemo(() => (doctype: string) => isDoctypeAllowed(doctypes, doctype), [doctypes]);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// Provider
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
export function BackofficeProvider({
|
|
201
|
+
children,
|
|
202
|
+
frappe,
|
|
203
|
+
navigation,
|
|
204
|
+
basePath = BACKOFFICE_BASE,
|
|
205
|
+
capabilities,
|
|
206
|
+
doctypes,
|
|
207
|
+
fields,
|
|
208
|
+
actions,
|
|
209
|
+
slots,
|
|
210
|
+
appearance,
|
|
211
|
+
onEvent,
|
|
212
|
+
i18nInstance,
|
|
213
|
+
}: BackofficeProviderProps) {
|
|
214
|
+
// Register the "backoffice" i18n namespace BEFORE children first render,
|
|
215
|
+
// so useTranslation("backoffice") is ready on the first pass (idempotent).
|
|
216
|
+
useState(() => {
|
|
217
|
+
registerBackofficeTranslations(i18nInstance);
|
|
218
|
+
return true;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Host field-registry overrides — applied during render (frappe-ui's
|
|
222
|
+
// registry is module-global) so first-pass field rendering sees them.
|
|
223
|
+
const appliedFields = useRef<Record<string, ComponentType<FieldRenderProps>>>({});
|
|
224
|
+
if (fields) {
|
|
225
|
+
for (const [fieldtype, component] of Object.entries(fields)) {
|
|
226
|
+
if (appliedFields.current[fieldtype] !== component) {
|
|
227
|
+
registerField(fieldtype, component);
|
|
228
|
+
appliedFields.current[fieldtype] = component;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Keep the handler on a ref so the wrapped navigator's identity survives
|
|
234
|
+
// inline `onEvent` props.
|
|
235
|
+
const onEventRef = useRef<BackofficeEventHandler | undefined>(onEvent);
|
|
236
|
+
onEventRef.current = onEvent;
|
|
237
|
+
|
|
238
|
+
const emitEvent = useMemo(
|
|
239
|
+
() => (event: BackofficeEvent) => {
|
|
240
|
+
onEventRef.current?.(event);
|
|
241
|
+
},
|
|
242
|
+
[],
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
// Wrap the host navigator so every navigation the backoffice performs
|
|
246
|
+
// lands on the event bus.
|
|
247
|
+
const wrappedNavigation = useMemo<BackofficeNavigator>(
|
|
248
|
+
() => ({
|
|
249
|
+
navigate: (path) => {
|
|
250
|
+
emitEvent({ type: "navigate", path, mode: "push" });
|
|
251
|
+
navigation.navigate(path);
|
|
252
|
+
},
|
|
253
|
+
replace: (path) => {
|
|
254
|
+
emitEvent({ type: "navigate", path, mode: "replace" });
|
|
255
|
+
navigation.replace(path);
|
|
256
|
+
},
|
|
257
|
+
back: () => {
|
|
258
|
+
emitEvent({
|
|
259
|
+
type: "navigate",
|
|
260
|
+
path: navigation.getLocation().path,
|
|
261
|
+
mode: "back",
|
|
262
|
+
});
|
|
263
|
+
navigation.back();
|
|
264
|
+
},
|
|
265
|
+
getLocation: () => navigation.getLocation(),
|
|
266
|
+
subscribe: (listener) => navigation.subscribe(listener),
|
|
267
|
+
}),
|
|
268
|
+
[navigation, emitEvent],
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const paths = useMemo(() => createBackofficePaths(basePath), [basePath]);
|
|
272
|
+
const resolvedCapabilities = useMemo(() => resolveCapabilities(capabilities), [capabilities]);
|
|
273
|
+
|
|
274
|
+
const config = useMemo<BackofficeConfig>(
|
|
275
|
+
() => ({
|
|
276
|
+
frappe,
|
|
277
|
+
navigation: wrappedNavigation,
|
|
278
|
+
basePath,
|
|
279
|
+
paths,
|
|
280
|
+
capabilities: resolvedCapabilities,
|
|
281
|
+
doctypes,
|
|
282
|
+
actions: actions ?? {},
|
|
283
|
+
slots: slots ?? {},
|
|
284
|
+
appearance,
|
|
285
|
+
emitEvent,
|
|
286
|
+
}),
|
|
287
|
+
[
|
|
288
|
+
frappe,
|
|
289
|
+
wrappedNavigation,
|
|
290
|
+
basePath,
|
|
291
|
+
paths,
|
|
292
|
+
resolvedCapabilities,
|
|
293
|
+
doctypes,
|
|
294
|
+
actions,
|
|
295
|
+
slots,
|
|
296
|
+
appearance,
|
|
297
|
+
emitEvent,
|
|
298
|
+
],
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<BackofficeConfigContext.Provider value={config}>
|
|
303
|
+
<FrappeProvider
|
|
304
|
+
baseURL={frappe.baseURL}
|
|
305
|
+
socketPort={frappe.socketPort}
|
|
306
|
+
auth={frappe.auth}
|
|
307
|
+
syncOptions={frappe.syncOptions}
|
|
308
|
+
socketOptions={frappe.socketOptions}
|
|
309
|
+
fixtures={frappe.fixtures}
|
|
310
|
+
>
|
|
311
|
+
{children}
|
|
312
|
+
</FrappeProvider>
|
|
313
|
+
</BackofficeConfigContext.Provider>
|
|
314
|
+
);
|
|
315
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoffice capability flags — the host's on/off (and per-feature config)
|
|
3
|
+
* switches for what the embedded backoffice displays and allows.
|
|
4
|
+
*
|
|
5
|
+
* Every flag accepts either a boolean or a config object; everything
|
|
6
|
+
* defaults ON so `<BackofficeProvider>` with no `capabilities` prop renders
|
|
7
|
+
* the full desk. Resolution happens once in the provider; surfaces read the
|
|
8
|
+
* resolved shape via `useBackofficeCapabilities()`.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { BACKOFFICE_VIEWS, type BackofficeView } from "../navigation/paths";
|
|
12
|
+
|
|
13
|
+
/** Boolean shorthand or per-feature config object. */
|
|
14
|
+
export type CapabilityInput<Config extends object = { enabled?: boolean }> =
|
|
15
|
+
| boolean
|
|
16
|
+
| (Config & { enabled?: boolean })
|
|
17
|
+
| undefined;
|
|
18
|
+
|
|
19
|
+
export interface BackofficeCapabilities {
|
|
20
|
+
/** Global search / command bar in the shell navbar. */
|
|
21
|
+
awesomebar?: CapabilityInput;
|
|
22
|
+
/** Notification bell + panel in the shell navbar. */
|
|
23
|
+
notifications?: CapabilityInput;
|
|
24
|
+
/** Avatar menu (profile, theme toggle, logout) in the shell navbar. */
|
|
25
|
+
userMenu?: CapabilityInput<{
|
|
26
|
+
/** Show the "Toggle Theme" item (needs an `appearance` adapter too). */
|
|
27
|
+
themeToggle?: boolean;
|
|
28
|
+
/** Show the "Log Out" item. */
|
|
29
|
+
logout?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* "Exit to site" escape hatch back into the host app (web only).
|
|
32
|
+
* `path` is host-app absolute (default "/"); `label` overrides the
|
|
33
|
+
* translated default.
|
|
34
|
+
*/
|
|
35
|
+
exitToSite?: boolean | { enabled?: boolean; path?: string; label?: string };
|
|
36
|
+
}>;
|
|
37
|
+
/** Help menu (docs links, shortcuts + about dialogs) in the shell navbar. */
|
|
38
|
+
help?: CapabilityInput;
|
|
39
|
+
/** Workspace sidebar (desktop rail + narrow drawer). */
|
|
40
|
+
sidebar?: CapabilityInput;
|
|
41
|
+
/** Quick-entry dialogs (compact create forms). */
|
|
42
|
+
quickEntry?: CapabilityInput;
|
|
43
|
+
/** List views. `allow` restricts which views are reachable. */
|
|
44
|
+
views?: CapabilityInput<{ allow?: readonly BackofficeView[] }>;
|
|
45
|
+
/** "New <doctype>" affordances (list header, awesomebar new-commands, …). */
|
|
46
|
+
newDoc?: CapabilityInput;
|
|
47
|
+
/** List bulk-action bar (multi-select edit/assign/tag/delete). */
|
|
48
|
+
bulkActions?: CapabilityInput;
|
|
49
|
+
/** Form sidebar attachments section. */
|
|
50
|
+
attachments?: CapabilityInput;
|
|
51
|
+
/** Form activity timeline (comments, versions, communications). */
|
|
52
|
+
timeline?: CapabilityInput;
|
|
53
|
+
/** Assignment (ToDo) surfaces on forms and lists. */
|
|
54
|
+
assignments?: CapabilityInput;
|
|
55
|
+
/** Tag surfaces on forms and lists. */
|
|
56
|
+
tags?: CapabilityInput;
|
|
57
|
+
/** Document share surfaces. */
|
|
58
|
+
shares?: CapabilityInput;
|
|
59
|
+
/** Print affordances. */
|
|
60
|
+
print?: CapabilityInput;
|
|
61
|
+
/** Email / communication affordances. */
|
|
62
|
+
email?: CapabilityInput;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface ResolvedCapability {
|
|
66
|
+
enabled: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ResolvedExitToSite {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
path: string;
|
|
72
|
+
label?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ResolvedBackofficeCapabilities {
|
|
76
|
+
awesomebar: ResolvedCapability;
|
|
77
|
+
notifications: ResolvedCapability;
|
|
78
|
+
userMenu: ResolvedCapability & {
|
|
79
|
+
themeToggle: boolean;
|
|
80
|
+
logout: boolean;
|
|
81
|
+
exitToSite: ResolvedExitToSite;
|
|
82
|
+
};
|
|
83
|
+
help: ResolvedCapability;
|
|
84
|
+
sidebar: ResolvedCapability;
|
|
85
|
+
quickEntry: ResolvedCapability;
|
|
86
|
+
views: ResolvedCapability & { allow: readonly BackofficeView[] };
|
|
87
|
+
newDoc: ResolvedCapability;
|
|
88
|
+
bulkActions: ResolvedCapability;
|
|
89
|
+
attachments: ResolvedCapability;
|
|
90
|
+
timeline: ResolvedCapability;
|
|
91
|
+
assignments: ResolvedCapability;
|
|
92
|
+
tags: ResolvedCapability;
|
|
93
|
+
shares: ResolvedCapability;
|
|
94
|
+
print: ResolvedCapability;
|
|
95
|
+
email: ResolvedCapability;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function resolveFlag<Resolved extends { enabled: boolean }>(
|
|
99
|
+
input: boolean | (Partial<Resolved> & { enabled?: boolean }) | undefined,
|
|
100
|
+
defaults: Resolved,
|
|
101
|
+
): Resolved {
|
|
102
|
+
if (input === undefined) return defaults;
|
|
103
|
+
if (typeof input === "boolean") return { ...defaults, enabled: input };
|
|
104
|
+
// Undefined config values must not clobber defaults (exactOptionalPropertyTypes).
|
|
105
|
+
const merged: Record<string, unknown> = { ...defaults };
|
|
106
|
+
for (const [key, value] of Object.entries(input)) {
|
|
107
|
+
if (value !== undefined) merged[key] = value;
|
|
108
|
+
}
|
|
109
|
+
merged.enabled = input.enabled ?? true;
|
|
110
|
+
return merged as Resolved;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function resolveExitToSite(
|
|
114
|
+
input: boolean | { enabled?: boolean; path?: string; label?: string } | undefined,
|
|
115
|
+
): ResolvedExitToSite {
|
|
116
|
+
if (input === undefined) return { enabled: true, path: "/" };
|
|
117
|
+
if (typeof input === "boolean") return { enabled: input, path: "/" };
|
|
118
|
+
const resolved: ResolvedExitToSite = { enabled: input.enabled ?? true, path: input.path ?? "/" };
|
|
119
|
+
if (input.label !== undefined) resolved.label = input.label;
|
|
120
|
+
return resolved;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function resolveCapabilities(
|
|
124
|
+
input: BackofficeCapabilities = {},
|
|
125
|
+
): ResolvedBackofficeCapabilities {
|
|
126
|
+
const userMenuInput = typeof input.userMenu === "object" ? input.userMenu : undefined;
|
|
127
|
+
return {
|
|
128
|
+
awesomebar: resolveFlag<ResolvedCapability>(input.awesomebar, { enabled: true }),
|
|
129
|
+
notifications: resolveFlag<ResolvedCapability>(input.notifications, { enabled: true }),
|
|
130
|
+
userMenu: {
|
|
131
|
+
enabled:
|
|
132
|
+
typeof input.userMenu === "boolean" ? input.userMenu : (userMenuInput?.enabled ?? true),
|
|
133
|
+
themeToggle: userMenuInput?.themeToggle ?? true,
|
|
134
|
+
logout: userMenuInput?.logout ?? true,
|
|
135
|
+
exitToSite: resolveExitToSite(userMenuInput?.exitToSite),
|
|
136
|
+
},
|
|
137
|
+
help: resolveFlag<ResolvedCapability>(input.help, { enabled: true }),
|
|
138
|
+
sidebar: resolveFlag<ResolvedCapability>(input.sidebar, { enabled: true }),
|
|
139
|
+
quickEntry: resolveFlag<ResolvedCapability>(input.quickEntry, { enabled: true }),
|
|
140
|
+
views: resolveFlag<ResolvedBackofficeCapabilities["views"]>(input.views, {
|
|
141
|
+
enabled: true,
|
|
142
|
+
allow: BACKOFFICE_VIEWS,
|
|
143
|
+
}),
|
|
144
|
+
newDoc: resolveFlag<ResolvedCapability>(input.newDoc, { enabled: true }),
|
|
145
|
+
bulkActions: resolveFlag<ResolvedCapability>(input.bulkActions, { enabled: true }),
|
|
146
|
+
attachments: resolveFlag<ResolvedCapability>(input.attachments, { enabled: true }),
|
|
147
|
+
timeline: resolveFlag<ResolvedCapability>(input.timeline, { enabled: true }),
|
|
148
|
+
assignments: resolveFlag<ResolvedCapability>(input.assignments, { enabled: true }),
|
|
149
|
+
tags: resolveFlag<ResolvedCapability>(input.tags, { enabled: true }),
|
|
150
|
+
shares: resolveFlag<ResolvedCapability>(input.shares, { enabled: true }),
|
|
151
|
+
print: resolveFlag<ResolvedCapability>(input.print, { enabled: true }),
|
|
152
|
+
email: resolveFlag<ResolvedCapability>(input.email, { enabled: true }),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Doctype reachability scope (allow wins over deny being absent; deny always wins). */
|
|
157
|
+
export interface BackofficeDoctypeScope {
|
|
158
|
+
/** When set, only these doctypes are reachable. */
|
|
159
|
+
allow?: readonly string[];
|
|
160
|
+
/** Always-unreachable doctypes (applied after `allow`). */
|
|
161
|
+
deny?: readonly string[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function isDoctypeAllowed(
|
|
165
|
+
scope: BackofficeDoctypeScope | undefined,
|
|
166
|
+
doctype: string,
|
|
167
|
+
): boolean {
|
|
168
|
+
if (!scope) return true;
|
|
169
|
+
if (scope.deny?.includes(doctype)) return false;
|
|
170
|
+
if (scope.allow && !scope.allow.includes(doctype)) return false;
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host event bus — `onEvent` on the provider receives every notable thing
|
|
3
|
+
* the embedded backoffice does, so host apps can sync their own chrome,
|
|
4
|
+
* analytics, or state.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type BackofficeEvent =
|
|
8
|
+
/** Any navigation performed through the backoffice navigator. */
|
|
9
|
+
| { type: "navigate"; path: string; mode: "push" | "replace" | "back" }
|
|
10
|
+
/** A document form was opened. */
|
|
11
|
+
| { type: "doc-opened"; doctype: string; name: string }
|
|
12
|
+
/** A document was saved (`isNew` for first inserts). */
|
|
13
|
+
| { type: "doc-saved"; doctype: string; name: string; isNew?: boolean }
|
|
14
|
+
/** A document was deleted. */
|
|
15
|
+
| { type: "doc-deleted"; doctype: string; name: string }
|
|
16
|
+
/** A surface caught an operational error worth surfacing to the host. */
|
|
17
|
+
| { type: "error"; error: unknown; context?: string };
|
|
18
|
+
|
|
19
|
+
export type BackofficeEventHandler = (event: BackofficeEvent) => void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Host render-prop slots — the highest-leverage replacement points. Slots
|
|
5
|
+
* are provider-level (they apply everywhere the surface renders); when a
|
|
6
|
+
* slot is undefined the built-in rendering is used.
|
|
7
|
+
*/
|
|
8
|
+
export interface BackofficeSlots {
|
|
9
|
+
/**
|
|
10
|
+
* Replace the shell navbar CONTENT (inside the styled banner bar).
|
|
11
|
+
* `defaultContent` is the built-in navbar row (home button, awesomebar,
|
|
12
|
+
* bell/help/user chrome) so hosts can wrap instead of rebuild.
|
|
13
|
+
*/
|
|
14
|
+
renderShellHeader?: (context: { defaultContent: ReactNode }) => ReactNode;
|
|
15
|
+
/** Rendered at the bottom of the workspace sidebar (rail and drawer). */
|
|
16
|
+
renderSidebarFooter?: () => ReactNode;
|
|
17
|
+
/** Replace the list screen's empty state. (Consumed by the list surface.) */
|
|
18
|
+
renderListEmpty?: (context: { doctype: string }) => ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Replace the document form header row. (Consumed by the form surface.)
|
|
21
|
+
* `name` is undefined for new (unsaved) documents.
|
|
22
|
+
*/
|
|
23
|
+
renderFormHeader?: (context: {
|
|
24
|
+
doctype: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
defaultContent: ReactNode;
|
|
27
|
+
}) => ReactNode;
|
|
28
|
+
}
|