@jskit-ai/agent-docs 0.1.148 → 0.1.150
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/guide/agent/app-setup/existing-application-migration.md +8 -6
- package/guide/agent/app-setup/initial-scaffolding.md +26 -7
- package/guide/agent/app-setup/quickstart.md +9 -6
- package/guide/agent/framework/application-operations.md +91 -0
- package/guide/agent/framework/crud-operations.md +83 -0
- package/guide/agent/framework/material-3.md +112 -0
- package/guide/agent/framework/ui-operations.md +78 -0
- package/guide/agent/index.md +13 -3
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/PATTERN.md +5 -0
- package/patterns/minimal-foundation/example/AGENTS.md +8 -8
- package/patterns/minimal-foundation/example/package.json +4 -5
- package/patterns/minimal-foundation/example/vite.config.mjs +0 -1
- package/patterns/shell-foundation/PATTERN.md +5 -0
- package/patterns/shell-foundation/example/AGENTS.md +8 -8
- package/patterns/shell-foundation/example/package.json +5 -6
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/vite.config.mjs +0 -1
- package/reference/autogen/PATTERN_INDEX.md +61 -61
- package/reference/autogen/tooling/testUtils.md +1 -1
- package/skills/jskit/SKILL.md +8 -5
- package/skills/jskit/references/app-operations.md +12 -11
- package/skills/jskit/references/crud-operations.md +10 -6
- package/skills/jskit/references/existing-application-migration.md +9 -12
- package/skills/jskit/references/material-3.md +2 -0
- package/skills/jskit/references/pattern-index.md +61 -61
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +105 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/.nvmrc +1 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +17 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/Procfile +2 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/app.json +14 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +71 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/server.js +8 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/public.js +40 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/server.js +1 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +19 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/favicon.svg +7 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/gitignore +9 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/index.html +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/jsconfig.json +8 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +62 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/package.json +42 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +31 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +195 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/App.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/main.js +85 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home/index.vue +48 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/src/views/NotFound.vue +13 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +16 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/vite.config.mjs +80 -0
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +111 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/.nvmrc +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +17 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/Procfile +2 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/app.json +14 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +71 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/server.js +8 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/public.js +40 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/server.js +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/favicon.svg +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/gitignore +9 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/index.html +13 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/jsconfig.json +8 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +64 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +56 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/index.js +9 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/index.js +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +31 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +195 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/App.vue +11 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/ShellLayout.vue +12 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/error.js +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/main.js +85 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/index.vue +116 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings.vue +109 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home.vue +20 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/placement.js +56 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/placementTopology.js +149 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/src/views/NotFound.vue +13 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +16 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/vite.config.mjs +80 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md +77 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/public.js +19 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/server.js +9 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/assistant/index.vue +7 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/settings/assistant/index.vue +7 -0
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/placement.js +38 -0
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +90 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/login.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/reset-password.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/signout.vue +17 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authGuardRuntime.js +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authHttpClient.js +1 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/useSignOut.js +1 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/LoginView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/ResetPasswordView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/SignOutView.vue +7 -0
- package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +5 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/PATTERN.md +67 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/.env.example +4 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/config/server.js +11 -0
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +7 -0
- package/skills/jskit/references/patterns/console/console-surface/PATTERN.md +58 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/index.vue +62 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings/index.vue +17 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings.vue +95 -0
- package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console.vue +20 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +88 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +54 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookFormFields.vue +52 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue +54 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +45 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookViewPage.vue +50 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/formFields.js +31 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/listExtensions.js +9 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +160 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/migrations/20260815000000_books.cjs +22 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +41 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/BooksFeature.js +13 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/bookResource.js +83 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +102 -0
- package/skills/jskit/references/patterns/crud/resource-contract/example/bookResource.js +87 -0
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +80 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/.env.example +5 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/.github/workflows/verify.yml +39 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +11 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +13 -0
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +3 -0
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +80 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/.env.example +5 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/.github/workflows/verify.yml +38 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +11 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +13 -0
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +3 -0
- package/skills/jskit/references/patterns/mobile/android-application/PATTERN.md +71 -0
- package/skills/jskit/references/patterns/mobile/android-application/example/capacitor.config.json +10 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md +69 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/.env.example +1 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +8 -0
- package/skills/jskit/references/patterns/realtime/realtime-application/example/src/placement.js +17 -0
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +108 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +48 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +34 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +23 -0
- package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +66 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/App.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home/index.vue +48 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/App.vue +11 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/ShellLayout.vue +13 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/MenuLinkItem.vue +30 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/TabLinkItem.vue +42 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/error.js +19 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/index.vue +106 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/general/index.vue +40 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/index.vue +7 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings.vue +109 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home.vue +20 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/placement.js +56 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/src/placementTopology.js +149 -0
- package/skills/jskit/references/patterns/shell/application-shell/example/tests/e2e/adaptive-shell.spec.ts +10 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md +76 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/packages/main/src/client/providers/MainClientProvider.js +14 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/components/SyncStatusElement.vue +16 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/activity.vue +8 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/index.vue +7 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/overview.vue +8 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue +33 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placement.js +52 -0
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +29 -0
- package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +61 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue +81 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +151 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +120 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/index.vue +17 -0
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +64 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +42 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/UsersFeature.js +13 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userResource.js +69 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +43 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +22 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/index.js +1 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userResource.js +56 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +60 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/config/roles.js +27 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +23 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md +63 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue +106 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountSettingsInvitesSection.vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/components/WorkspaceNotFoundCard.vue +53 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/composables/useWorkspaceNotFoundState.js +41 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/members/index.vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings/index.vue +23 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings.vue +95 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/invite/[token].vue +7 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/index.vue +85 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/root.vue +20 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/index.vue +46 -0
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/root.vue +20 -0
- package/skills/jskit/references/ui-operations.md +5 -3
- package/templates/app/AGENTS.md +8 -8
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
|
|
2
|
+
|
|
3
|
+
const resource = defineCrudResource({
|
|
4
|
+
namespace: "users",
|
|
5
|
+
tableName: "users",
|
|
6
|
+
crudOperations: ["list", "view"],
|
|
7
|
+
schema: {
|
|
8
|
+
name: {
|
|
9
|
+
type: "string",
|
|
10
|
+
required: true,
|
|
11
|
+
minLength: 1,
|
|
12
|
+
maxLength: 160,
|
|
13
|
+
actualField: "display_name",
|
|
14
|
+
search: true,
|
|
15
|
+
operations: {
|
|
16
|
+
output: { required: false }
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
email: {
|
|
20
|
+
type: "string",
|
|
21
|
+
required: true,
|
|
22
|
+
search: true,
|
|
23
|
+
operations: {
|
|
24
|
+
output: { required: false }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
username: {
|
|
28
|
+
type: "string",
|
|
29
|
+
required: true,
|
|
30
|
+
search: true,
|
|
31
|
+
operations: {
|
|
32
|
+
output: { required: false }
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
createdAt: {
|
|
36
|
+
type: "dateTime",
|
|
37
|
+
required: true,
|
|
38
|
+
storage: { writeSerializer: "datetime-utc" },
|
|
39
|
+
operations: {
|
|
40
|
+
output: { required: true }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
updatedAt: {
|
|
44
|
+
type: "dateTime",
|
|
45
|
+
required: true,
|
|
46
|
+
storage: { writeSerializer: "datetime-utc" },
|
|
47
|
+
operations: {
|
|
48
|
+
output: { required: true }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
searchSchema: {
|
|
53
|
+
id: {
|
|
54
|
+
type: "id",
|
|
55
|
+
actualField: "id"
|
|
56
|
+
},
|
|
57
|
+
q: {
|
|
58
|
+
type: "string",
|
|
59
|
+
oneOf: ["name", "email", "username"],
|
|
60
|
+
filterOperator: "like",
|
|
61
|
+
splitBy: " ",
|
|
62
|
+
matchAll: true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
defaultSort: ["name", "email"],
|
|
66
|
+
autofilter: "public"
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export { resource };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@app/users-workspace",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "App-local workspace-scoped read-only user administration feature.",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./server/UsersWorkspaceFeature": "./src/server/UsersWorkspaceFeature.js",
|
|
9
|
+
"./shared": "./src/shared/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@jskit-ai/crud-core": "0.1.189",
|
|
13
|
+
"@jskit-ai/resource-crud-core": "0.1.120",
|
|
14
|
+
"@jskit-ai/workspaces-core": "0.1.156"
|
|
15
|
+
},
|
|
16
|
+
"jskit": {
|
|
17
|
+
"kind": "runtime",
|
|
18
|
+
"capabilities": {
|
|
19
|
+
"provides": [
|
|
20
|
+
"app.users-workspace"
|
|
21
|
+
],
|
|
22
|
+
"requires": [
|
|
23
|
+
"runtime.http",
|
|
24
|
+
"runtime.json-rest-api",
|
|
25
|
+
"runtime.actions",
|
|
26
|
+
"runtime.database"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"runtime": {
|
|
30
|
+
"server": {
|
|
31
|
+
"providers": [
|
|
32
|
+
{
|
|
33
|
+
"entrypoint": "src/server/UsersWorkspaceFeature.js",
|
|
34
|
+
"export": "UsersWorkspaceFeature"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"client": {
|
|
39
|
+
"providers": []
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineCrudJsonApiFeature } from "@jskit-ai/crud-core/server/defineCrudJsonApiFeature";
|
|
2
|
+
import { buildWorkspaceInputFromRouteParams } from "@jskit-ai/workspaces-core/server/support/workspaceRouteInput";
|
|
3
|
+
import { workspaceSlugParamsValidator } from "@jskit-ai/workspaces-core/server/validators/routeParamsValidator";
|
|
4
|
+
import { resource } from "../shared/userResource.js";
|
|
5
|
+
|
|
6
|
+
const UsersWorkspaceFeature = defineCrudJsonApiFeature({
|
|
7
|
+
resource,
|
|
8
|
+
id: "app.users-workspace",
|
|
9
|
+
capability: "app.users-workspace",
|
|
10
|
+
surface: "admin",
|
|
11
|
+
ownershipFilter: "workspace",
|
|
12
|
+
relativePath: "/users",
|
|
13
|
+
scope: {
|
|
14
|
+
routeBase: "/w/:workspaceSlug",
|
|
15
|
+
actionInputValidator: workspaceSlugParamsValidator,
|
|
16
|
+
routeParamsValidator: workspaceSlugParamsValidator,
|
|
17
|
+
inputKeys: ["workspaceSlug"],
|
|
18
|
+
input: (request) => buildWorkspaceInputFromRouteParams(request.input.params)
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export { UsersWorkspaceFeature };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { resource } from "./userResource.js";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { defineCrudResource } from "@jskit-ai/resource-crud-core/shared/crudResource";
|
|
2
|
+
|
|
3
|
+
const resource = defineCrudResource({
|
|
4
|
+
namespace: "users",
|
|
5
|
+
tableName: "users",
|
|
6
|
+
crudOperations: ["list", "view"],
|
|
7
|
+
schema: {
|
|
8
|
+
name: {
|
|
9
|
+
type: "string",
|
|
10
|
+
required: true,
|
|
11
|
+
minLength: 1,
|
|
12
|
+
maxLength: 160,
|
|
13
|
+
actualField: "display_name",
|
|
14
|
+
search: true,
|
|
15
|
+
operations: { output: { required: false } }
|
|
16
|
+
},
|
|
17
|
+
email: {
|
|
18
|
+
type: "string",
|
|
19
|
+
required: true,
|
|
20
|
+
search: true,
|
|
21
|
+
operations: { output: { required: false } }
|
|
22
|
+
},
|
|
23
|
+
username: {
|
|
24
|
+
type: "string",
|
|
25
|
+
required: true,
|
|
26
|
+
search: true,
|
|
27
|
+
operations: { output: { required: false } }
|
|
28
|
+
},
|
|
29
|
+
createdAt: {
|
|
30
|
+
type: "dateTime",
|
|
31
|
+
required: true,
|
|
32
|
+
storage: { writeSerializer: "datetime-utc" },
|
|
33
|
+
operations: { output: { required: true } }
|
|
34
|
+
},
|
|
35
|
+
updatedAt: {
|
|
36
|
+
type: "dateTime",
|
|
37
|
+
required: true,
|
|
38
|
+
storage: { writeSerializer: "datetime-utc" },
|
|
39
|
+
operations: { output: { required: true } }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
searchSchema: {
|
|
43
|
+
id: { type: "id", actualField: "id" },
|
|
44
|
+
q: {
|
|
45
|
+
type: "string",
|
|
46
|
+
oneOf: ["name", "email", "username"],
|
|
47
|
+
filterOperator: "like",
|
|
48
|
+
splitBy: " ",
|
|
49
|
+
matchAll: true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
defaultSort: ["name", "email"],
|
|
53
|
+
autofilter: "public"
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export { resource };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: workspaces/workspace-server
|
|
3
|
+
title: Workspace tenancy server composition
|
|
4
|
+
summary: Configure roles, workspace access policy, invitations, and app-owned invitation email rendering around JSKIT workspace runtime APIs.
|
|
5
|
+
keywords: access, invite, membership, multitenancy, policy, role, tenancy, workspace
|
|
6
|
+
requires: @jskit-ai/workspaces-core, @jskit-ai/users-core
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Workspace tenancy server composition
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when records, routes, or navigation belong to a selected
|
|
14
|
+
workspace and membership or role affects access.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
Do not use workspace tenancy for a genuinely single-owner product or as a
|
|
19
|
+
substitute for a simpler domain ownership column.
|
|
20
|
+
|
|
21
|
+
## Product decisions
|
|
22
|
+
|
|
23
|
+
Choose workspace creation policy, roles, invitation policy, expiry, email copy,
|
|
24
|
+
member permissions, personal-workspace behavior, and surface access rules.
|
|
25
|
+
|
|
26
|
+
## Framework APIs
|
|
27
|
+
|
|
28
|
+
Use workspace routes, resources, scope helpers, tenancy profiles, and settings
|
|
29
|
+
contracts exported by `@jskit-ai/workspaces-core`.
|
|
30
|
+
|
|
31
|
+
## Invariants
|
|
32
|
+
|
|
33
|
+
- Workspace membership and role are checked before scoped application actions.
|
|
34
|
+
- Role ids are stable product vocabulary shared by server and client config.
|
|
35
|
+
- Invitation tokens remain secret; emails receive only the intended link.
|
|
36
|
+
- Workspace scope reaches repository queries, not just route parsing.
|
|
37
|
+
- Package-owned migrations run directly from the installed package graph.
|
|
38
|
+
|
|
39
|
+
## Example files
|
|
40
|
+
|
|
41
|
+
`example/config/roles.js` is a concrete role catalogue.
|
|
42
|
+
`example/packages/main/src/server/email/workspaceInviteEmail.js` demonstrates an
|
|
43
|
+
app-owned invitation renderer. Compose both through normal application config.
|
|
44
|
+
|
|
45
|
+
## Variation points
|
|
46
|
+
|
|
47
|
+
Change roles, invitation policy and copy, defaults, access policies, surface
|
|
48
|
+
ids, and product-specific workspace settings.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
Test create/list/select, member and non-member access, each role boundary,
|
|
53
|
+
invitation expiry/redemption, cross-workspace isolation, and email output.
|
|
54
|
+
|
|
55
|
+
## Avoid
|
|
56
|
+
|
|
57
|
+
- synthetic membership workarounds
|
|
58
|
+
- authorizing from client navigation state
|
|
59
|
+
- embedding invitation templates or secrets in package metadata
|
|
60
|
+
- source-appending install commands
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const roleCatalog = {
|
|
2
|
+
workspace: {
|
|
3
|
+
defaultInviteRole: "member"
|
|
4
|
+
},
|
|
5
|
+
roles: {
|
|
6
|
+
owner: {
|
|
7
|
+
assignable: false,
|
|
8
|
+
permissions: ["*"]
|
|
9
|
+
},
|
|
10
|
+
admin: {
|
|
11
|
+
assignable: true,
|
|
12
|
+
inherits: "member",
|
|
13
|
+
permissions: [
|
|
14
|
+
"workspace.roles.view",
|
|
15
|
+
"workspace.settings.update",
|
|
16
|
+
"workspace.members.view",
|
|
17
|
+
"workspace.members.invite",
|
|
18
|
+
"workspace.members.manage",
|
|
19
|
+
"workspace.invites.revoke"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
member: {
|
|
23
|
+
assignable: true,
|
|
24
|
+
permissions: ["workspace.settings.view"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function renderWorkspaceInviteEmail({
|
|
2
|
+
inviteUrl = "",
|
|
3
|
+
workspace = {},
|
|
4
|
+
inviter = null,
|
|
5
|
+
roleSid = "member",
|
|
6
|
+
expiresAt = ""
|
|
7
|
+
} = {}) {
|
|
8
|
+
const workspaceName = String(workspace?.name || workspace?.slug || "the workspace").trim() || "the workspace";
|
|
9
|
+
const inviterName = String(inviter?.displayName || inviter?.email || "").trim();
|
|
10
|
+
const roleName = String(roleSid || "member").trim() || "member";
|
|
11
|
+
const intro = inviterName
|
|
12
|
+
? `${inviterName} invited you to join ${workspaceName} as ${roleName}.`
|
|
13
|
+
: `You have been invited to join ${workspaceName} as ${roleName}.`;
|
|
14
|
+
const expiryText = expiresAt ? `This invitation expires at ${expiresAt}.` : "";
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
subject: `You're invited to ${workspaceName}`,
|
|
18
|
+
text: [intro, expiryText, "Open this link to accept the invitation:", inviteUrl].filter(Boolean).join("\n\n"),
|
|
19
|
+
html: null
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export { renderWorkspaceInviteEmail };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: workspaces/workspace-surfaces
|
|
3
|
+
title: Workspace application and administration surfaces
|
|
4
|
+
summary: Compose workspace selection, invitation, member administration, settings, and responsive navigation using JSKIT workspace web APIs.
|
|
5
|
+
keywords: admin, invite, member, navigation, settings, surface, switcher, workspace
|
|
6
|
+
requires: @jskit-ai/workspaces-core, @jskit-ai/workspaces-web, @jskit-ai/shell-web
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Workspace application and administration surfaces
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern when the product has workspace-scoped app and administration
|
|
14
|
+
surfaces, invitations, member management, or workspace switching.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
Do not use this pattern for a single-owner application, or copy its whole
|
|
19
|
+
surface tree when only one workspace widget is needed.
|
|
20
|
+
|
|
21
|
+
## Product decisions
|
|
22
|
+
|
|
23
|
+
Choose public invitation routes, application/admin surface ids, workspace
|
|
24
|
+
selector behavior, member-management permissions, settings sections, and the
|
|
25
|
+
empty or not-found experience.
|
|
26
|
+
|
|
27
|
+
## Framework APIs
|
|
28
|
+
|
|
29
|
+
Use the workspace client provider, components, and composables exported by
|
|
30
|
+
`@jskit-ai/workspaces-web` together with JSKIT shell placements and routes.
|
|
31
|
+
|
|
32
|
+
## Invariants
|
|
33
|
+
|
|
34
|
+
- Route workspace slug, selected workspace, and server scope stay synchronized.
|
|
35
|
+
- Invitation acceptance is public only where the server contract permits it.
|
|
36
|
+
- Administrative UI visibility never substitutes for server authorization.
|
|
37
|
+
- Query and route state hydrate immediately on warm-cache navigation.
|
|
38
|
+
- Loading uses skeletons; mutation failures use toasts without layout movement.
|
|
39
|
+
- Navigation is composed through semantic placements and registered tokens.
|
|
40
|
+
|
|
41
|
+
## Example files
|
|
42
|
+
|
|
43
|
+
`example/` contains workspace app/admin roots, starter pages, invitation route,
|
|
44
|
+
member and settings routes, not-found state, app-owned invitation widgets, and
|
|
45
|
+
the components that an application's client provider registers.
|
|
46
|
+
|
|
47
|
+
## Variation points
|
|
48
|
+
|
|
49
|
+
Change surfaces, routes, section owners, labels, icons, placement order,
|
|
50
|
+
workspace-not-found copy, member operations, and invitation presentation.
|
|
51
|
+
|
|
52
|
+
## Verification
|
|
53
|
+
|
|
54
|
+
Exercise direct workspace URLs, selection and switching, invitations, members,
|
|
55
|
+
settings, not-found state, browser back/forward, forbidden access, and all
|
|
56
|
+
responsive navigation variants.
|
|
57
|
+
|
|
58
|
+
## Avoid
|
|
59
|
+
|
|
60
|
+
- defaulting silently to another workspace after an invalid route
|
|
61
|
+
- unscoped queries
|
|
62
|
+
- inline mutation error banners
|
|
63
|
+
- generated placement or source mutation machinery
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import { useRoute } from "vue-router";
|
|
4
|
+
import { mdiEmailAlertOutline } from "@mdi/js";
|
|
5
|
+
import { appendQueryString } from "@jskit-ai/kernel/shared/support";
|
|
6
|
+
import {
|
|
7
|
+
useWebPlacementContext,
|
|
8
|
+
resolveSurfaceDefinitionFromPlacementContext,
|
|
9
|
+
resolveSurfacePathFromPlacementContext,
|
|
10
|
+
resolveSurfaceNavigationTargetFromPlacementContext
|
|
11
|
+
} from "@jskit-ai/shell-web/client/placement";
|
|
12
|
+
|
|
13
|
+
const { context: placementContext } = useWebPlacementContext();
|
|
14
|
+
const route = useRoute();
|
|
15
|
+
|
|
16
|
+
function normalizePendingInvitesCount(value) {
|
|
17
|
+
const numeric = Number(value);
|
|
18
|
+
if (!Number.isInteger(numeric) || numeric < 1) {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
return numeric;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveReturnTo() {
|
|
25
|
+
const fullPath = String(route?.fullPath || "").trim();
|
|
26
|
+
if (fullPath.startsWith("/") && !fullPath.startsWith("//")) {
|
|
27
|
+
return fullPath;
|
|
28
|
+
}
|
|
29
|
+
const path = String(route?.path || "").trim();
|
|
30
|
+
if (path.startsWith("/") && !path.startsWith("//")) {
|
|
31
|
+
return path;
|
|
32
|
+
}
|
|
33
|
+
return "/";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function resolveReturnToHref() {
|
|
37
|
+
if (typeof window === "object" && window?.location?.href) {
|
|
38
|
+
return String(window.location.href || "").trim() || resolveReturnTo();
|
|
39
|
+
}
|
|
40
|
+
return resolveReturnTo();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const authenticated = computed(() => placementContext.value?.auth?.authenticated === true);
|
|
44
|
+
const placementPendingInvitesCount = computed(() =>
|
|
45
|
+
normalizePendingInvitesCount(placementContext.value?.pendingInvitesCount)
|
|
46
|
+
);
|
|
47
|
+
const pendingInvitesCount = computed(() => placementPendingInvitesCount.value);
|
|
48
|
+
const placementWorkspaceInvitesEnabled = computed(() => placementContext.value?.workspaceInvitesEnabled === true);
|
|
49
|
+
const workspaceInvitesEnabled = computed(() => placementWorkspaceInvitesEnabled.value);
|
|
50
|
+
|
|
51
|
+
const isVisible = computed(() => {
|
|
52
|
+
return (
|
|
53
|
+
authenticated.value &&
|
|
54
|
+
workspaceInvitesEnabled.value &&
|
|
55
|
+
pendingInvitesCount.value > 0
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const resolvedTo = computed(() => {
|
|
60
|
+
const hasAccountSurface = Boolean(resolveSurfaceDefinitionFromPlacementContext(placementContext.value, "account"));
|
|
61
|
+
const accountSettingsPath = hasAccountSurface
|
|
62
|
+
? resolveSurfacePathFromPlacementContext(placementContext.value, "account", "/")
|
|
63
|
+
: "/account";
|
|
64
|
+
const accountSettingsNavigation = resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
65
|
+
path: accountSettingsPath,
|
|
66
|
+
surfaceId: "account"
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const query = new URLSearchParams({
|
|
70
|
+
section: "invites",
|
|
71
|
+
returnTo: accountSettingsNavigation.sameOrigin ? resolveReturnTo() : resolveReturnToHref()
|
|
72
|
+
});
|
|
73
|
+
return appendQueryString(accountSettingsPath, query.toString());
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const resolvedNavigationTarget = computed(() =>
|
|
77
|
+
resolveSurfaceNavigationTargetFromPlacementContext(placementContext.value, {
|
|
78
|
+
path: resolvedTo.value,
|
|
79
|
+
surfaceId: "account"
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<template>
|
|
85
|
+
<v-badge
|
|
86
|
+
v-if="isVisible"
|
|
87
|
+
color="error"
|
|
88
|
+
:content="pendingInvitesCount"
|
|
89
|
+
:model-value="pendingInvitesCount > 0"
|
|
90
|
+
bordered
|
|
91
|
+
offset-x="6"
|
|
92
|
+
offset-y="8"
|
|
93
|
+
>
|
|
94
|
+
<v-btn
|
|
95
|
+
:to="resolvedNavigationTarget.sameOrigin ? resolvedNavigationTarget.href : undefined"
|
|
96
|
+
:href="resolvedNavigationTarget.sameOrigin ? undefined : resolvedNavigationTarget.href"
|
|
97
|
+
variant="tonal"
|
|
98
|
+
color="warning"
|
|
99
|
+
:prepend-icon="mdiEmailAlertOutline"
|
|
100
|
+
size="small"
|
|
101
|
+
class="text-none"
|
|
102
|
+
>
|
|
103
|
+
Invites
|
|
104
|
+
</v-btn>
|
|
105
|
+
</v-badge>
|
|
106
|
+
</template>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { mdiAlertCircleOutline } from "@mdi/js";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
surfaceLabel: {
|
|
7
|
+
type: String,
|
|
8
|
+
default: "Workspace"
|
|
9
|
+
},
|
|
10
|
+
message: {
|
|
11
|
+
type: String,
|
|
12
|
+
default: "Workspace is currently unavailable."
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const normalizedSurfaceLabel = computed(() => String(props.surfaceLabel || "").trim() || "Workspace");
|
|
17
|
+
const normalizedMessage = computed(() => String(props.message || "").trim() || "Workspace is currently unavailable.");
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<v-sheet rounded="lg" border class="workspace-unavailable-panel">
|
|
22
|
+
<div class="workspace-unavailable-panel__header">
|
|
23
|
+
<v-icon :icon="mdiAlertCircleOutline" color="error" />
|
|
24
|
+
<div>
|
|
25
|
+
<h1 class="workspace-unavailable-panel__title">Unavailable</h1>
|
|
26
|
+
<p class="text-body-2 text-medium-emphasis mb-0">{{ normalizedSurfaceLabel }} surface.</p>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<p class="text-body-2 text-medium-emphasis mb-0">{{ normalizedMessage }}</p>
|
|
30
|
+
</v-sheet>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<style scoped>
|
|
34
|
+
.workspace-unavailable-panel {
|
|
35
|
+
display: grid;
|
|
36
|
+
gap: 1rem;
|
|
37
|
+
padding: 1rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.workspace-unavailable-panel__header {
|
|
41
|
+
align-items: flex-start;
|
|
42
|
+
display: flex;
|
|
43
|
+
gap: 0.75rem;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.workspace-unavailable-panel__title {
|
|
47
|
+
font-size: clamp(1.35rem, 2vw, 1.85rem);
|
|
48
|
+
font-weight: 650;
|
|
49
|
+
letter-spacing: -0.02em;
|
|
50
|
+
line-height: 1.15;
|
|
51
|
+
margin: 0 0 0.25rem;
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { useRoute } from "vue-router";
|
|
3
|
+
import { normalizeLowerText, normalizeObject } from "@jskit-ai/kernel/shared/support/normalize";
|
|
4
|
+
import { useWebPlacementContext } from "@jskit-ai/shell-web/client/placement";
|
|
5
|
+
|
|
6
|
+
const STATUS_MESSAGES = {
|
|
7
|
+
not_found: "The requested workspace was not found.",
|
|
8
|
+
forbidden: "You do not have access to this workspace.",
|
|
9
|
+
unauthenticated: "You need to sign in to access this workspace.",
|
|
10
|
+
error: "Workspace data could not be loaded right now."
|
|
11
|
+
};
|
|
12
|
+
const DEFAULT_WORKSPACE_UNAVAILABLE_MESSAGE = "Workspace is currently unavailable.";
|
|
13
|
+
const RESOLVED_WORKSPACE_STATUS = "resolved";
|
|
14
|
+
|
|
15
|
+
function useWorkspaceNotFoundState() {
|
|
16
|
+
const route = useRoute();
|
|
17
|
+
const { context: placementContext } = useWebPlacementContext();
|
|
18
|
+
|
|
19
|
+
const routeWorkspaceSlug = computed(() => normalizeLowerText(route?.params?.workspaceSlug));
|
|
20
|
+
|
|
21
|
+
const workspaceBootstrapStatus = computed(() => {
|
|
22
|
+
const statuses = normalizeObject(placementContext.value?.workspaceBootstrapStatuses);
|
|
23
|
+
return normalizeLowerText(statuses[routeWorkspaceSlug.value]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const workspaceUnavailable = computed(
|
|
27
|
+
() => Boolean(workspaceBootstrapStatus.value) && workspaceBootstrapStatus.value !== RESOLVED_WORKSPACE_STATUS
|
|
28
|
+
);
|
|
29
|
+
const workspaceUnavailableMessage = computed(
|
|
30
|
+
() => STATUS_MESSAGES[workspaceBootstrapStatus.value] || DEFAULT_WORKSPACE_UNAVAILABLE_MESSAGE
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return Object.freeze({
|
|
34
|
+
routeWorkspaceSlug,
|
|
35
|
+
workspaceBootstrapStatus,
|
|
36
|
+
workspaceUnavailable,
|
|
37
|
+
workspaceUnavailableMessage
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { useWorkspaceNotFoundState };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section class="workspace-settings-landing">
|
|
3
|
+
<v-sheet rounded="lg" border class="workspace-settings-landing__panel">
|
|
4
|
+
<h2 class="workspace-settings-landing__title">No settings sections yet</h2>
|
|
5
|
+
<p class="text-body-2 text-medium-emphasis mb-0">
|
|
6
|
+
This app has no workspace-level settings configured.
|
|
7
|
+
</p>
|
|
8
|
+
</v-sheet>
|
|
9
|
+
</section>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<style scoped>
|
|
13
|
+
.workspace-settings-landing__panel {
|
|
14
|
+
padding: 1rem;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.workspace-settings-landing__title {
|
|
18
|
+
font-size: 1rem;
|
|
19
|
+
font-weight: 650;
|
|
20
|
+
line-height: 1.2;
|
|
21
|
+
margin: 0 0 0.25rem;
|
|
22
|
+
}
|
|
23
|
+
</style>
|