@jskit-ai/workspaces-web 0.1.14 → 0.1.16

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.
Files changed (48) hide show
  1. package/package.descriptor.mjs +61 -25
  2. package/package.json +13 -3
  3. package/src/client/account-settings/accountSettingsInvitesRuntime.js +88 -0
  4. package/src/client/account-settings/useAccountSettingsInvitesSectionRuntime.js +217 -0
  5. package/src/client/components/AccountSettingsInvitesSection.vue +72 -0
  6. package/src/client/components/MembersAdminClientElement.vue +400 -0
  7. package/src/client/components/UsersProfileSurfaceSwitchMenuItem.vue +39 -0
  8. package/src/client/components/UsersWorkspaceMembersMenuItem.vue +36 -0
  9. package/src/client/components/UsersWorkspacePermissionMenuItem.vue +89 -0
  10. package/src/client/components/UsersWorkspaceSelector.vue +242 -0
  11. package/src/client/components/UsersWorkspaceSettingsMenuItem.vue +39 -0
  12. package/src/client/components/UsersWorkspaceToolsWidget.vue +12 -0
  13. package/src/client/components/WorkspaceMembersClientElement.vue +657 -0
  14. package/src/client/components/WorkspaceProfileClientElement.vue +116 -0
  15. package/src/client/components/WorkspaceSettingsClientElement.vue +102 -0
  16. package/src/client/components/WorkspaceSettingsFieldsClientElement.vue +265 -0
  17. package/src/client/components/WorkspacesClientElement.vue +540 -0
  18. package/src/client/composables/useBootstrapQuery.js +52 -0
  19. package/src/client/composables/useWorkspaceRouteContext.js +28 -0
  20. package/src/client/composables/useWorkspaceSurfaceId.js +43 -0
  21. package/src/client/index.js +1 -0
  22. package/src/client/lib/bootstrap.js +59 -0
  23. package/src/client/lib/httpClient.js +10 -0
  24. package/src/client/lib/permissions.js +27 -0
  25. package/src/client/lib/profileSurfaceMenuLinks.js +163 -0
  26. package/src/client/lib/surfaceAccessPolicy.js +350 -0
  27. package/src/client/lib/theme.js +332 -0
  28. package/src/client/lib/workspaceLinkResolver.js +207 -0
  29. package/src/client/lib/workspaceSurfaceContext.js +82 -0
  30. package/src/client/lib/workspaceSurfacePaths.js +163 -0
  31. package/src/client/providers/WorkspacesWebClientProvider.js +59 -2
  32. package/src/client/runtime/bootstrapPlacementRouteGuards.js +371 -0
  33. package/src/client/runtime/bootstrapPlacementRuntime.js +463 -0
  34. package/src/client/runtime/bootstrapPlacementRuntimeConstants.js +28 -0
  35. package/src/client/runtime/bootstrapPlacementRuntimeHelpers.js +147 -0
  36. package/src/client/support/realtimeWorkspace.js +21 -0
  37. package/src/client/support/runtimeNormalization.js +23 -0
  38. package/src/client/support/workspaceQueryKeys.js +15 -0
  39. package/src/shared/toolsOutletContracts.js +9 -0
  40. package/templates/src/pages/admin/members/index.vue +1 -1
  41. package/test/bootstrapPlacementRuntime.test.js +1095 -0
  42. package/test/exportsContract.test.js +2 -1
  43. package/test/profileSurfaceMenuLinks.test.js +208 -0
  44. package/test/settingsPlacementContract.test.js +19 -1
  45. package/test/surfaceAccessPolicy.test.js +129 -0
  46. package/test/theme.test.js +101 -0
  47. package/test/workspaceLinkResolver.test.js +61 -0
  48. package/test/workspaceSurfacePaths.test.js +39 -0
@@ -0,0 +1,332 @@
1
+ import { ThemeSymbol } from "vuetify/lib/composables/theme.js";
2
+ import { resolveWorkspaceThemePalette } from "@jskit-ai/workspaces-core/shared/settings";
3
+
4
+ const THEME_PREFERENCE_LIGHT = "light";
5
+ const THEME_PREFERENCE_DARK = "dark";
6
+ const THEME_PREFERENCE_SYSTEM = "system";
7
+ const HEX_COLOR_PATTERN = /^#[0-9A-Fa-f]{6}$/;
8
+ const WORKSPACE_THEME_NAME_LIGHT = "workspace-light";
9
+ const WORKSPACE_THEME_NAME_DARK = "workspace-dark";
10
+
11
+ function normalizeThemePreference(value) {
12
+ const normalized = String(value || "").trim().toLowerCase();
13
+ if (normalized === THEME_PREFERENCE_LIGHT || normalized === THEME_PREFERENCE_DARK) {
14
+ return normalized;
15
+ }
16
+ return THEME_PREFERENCE_SYSTEM;
17
+ }
18
+
19
+ function resolveSystemThemeName({ prefersDark } = {}) {
20
+ if (typeof prefersDark === "boolean") {
21
+ return prefersDark ? THEME_PREFERENCE_DARK : THEME_PREFERENCE_LIGHT;
22
+ }
23
+
24
+ if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
25
+ const prefersDarkFromMedia = window.matchMedia("(prefers-color-scheme: dark)").matches;
26
+ return prefersDarkFromMedia ? THEME_PREFERENCE_DARK : THEME_PREFERENCE_LIGHT;
27
+ }
28
+
29
+ return THEME_PREFERENCE_LIGHT;
30
+ }
31
+
32
+ function resolveThemeNameForPreference(themePreference, options = {}) {
33
+ const normalizedPreference = normalizeThemePreference(themePreference);
34
+ if (normalizedPreference === THEME_PREFERENCE_DARK) {
35
+ return THEME_PREFERENCE_DARK;
36
+ }
37
+ if (normalizedPreference === THEME_PREFERENCE_LIGHT) {
38
+ return THEME_PREFERENCE_LIGHT;
39
+ }
40
+
41
+ return resolveSystemThemeName(options);
42
+ }
43
+
44
+ function resolveThemePreferenceStorage(options = {}) {
45
+ const customStorage = options && typeof options === "object" ? options.storage : null;
46
+ if (customStorage && typeof customStorage === "object") {
47
+ return customStorage;
48
+ }
49
+
50
+ if (typeof window !== "object" || !window) {
51
+ return null;
52
+ }
53
+
54
+ let storage = null;
55
+ try {
56
+ storage = window.localStorage;
57
+ } catch {
58
+ return null;
59
+ }
60
+ if (!storage || typeof storage !== "object") {
61
+ return null;
62
+ }
63
+ return storage;
64
+ }
65
+
66
+ function readPersistedThemePreference(options = {}) {
67
+ const storage = resolveThemePreferenceStorage(options);
68
+ if (!storage || typeof storage.getItem !== "function") {
69
+ return THEME_PREFERENCE_SYSTEM;
70
+ }
71
+
72
+ try {
73
+ const value = storage.getItem("jskit.themePreference");
74
+ return normalizeThemePreference(value);
75
+ } catch {
76
+ return THEME_PREFERENCE_SYSTEM;
77
+ }
78
+ }
79
+
80
+ function persistThemePreference(themePreference, options = {}) {
81
+ const storage = resolveThemePreferenceStorage(options);
82
+ if (!storage || typeof storage.setItem !== "function") {
83
+ return false;
84
+ }
85
+
86
+ const normalizedPreference = normalizeThemePreference(themePreference);
87
+ try {
88
+ storage.setItem("jskit.themePreference", normalizedPreference);
89
+ return true;
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
95
+ function resolveBootstrapThemePreference(payload = {}, options = {}) {
96
+ const source = payload && typeof payload === "object" ? payload : {};
97
+ const session = source.session && typeof source.session === "object" ? source.session : {};
98
+ if (session.authenticated === true) {
99
+ const userSettings = source.userSettings && typeof source.userSettings === "object" ? source.userSettings : {};
100
+ return normalizeThemePreference(userSettings.theme);
101
+ }
102
+
103
+ return readPersistedThemePreference(options);
104
+ }
105
+
106
+ function resolveBootstrapThemeName(payload = {}, options = {}) {
107
+ return resolveThemeNameForPreference(resolveBootstrapThemePreference(payload, options), options);
108
+ }
109
+
110
+ function persistBootstrapThemePreference(payload = {}, options = {}) {
111
+ const source = payload && typeof payload === "object" ? payload : {};
112
+ const session = source.session && typeof source.session === "object" ? source.session : {};
113
+ if (session.authenticated !== true) {
114
+ return false;
115
+ }
116
+
117
+ return persistThemePreference(resolveBootstrapThemePreference(payload, options), options);
118
+ }
119
+
120
+ function resolveVuetifyThemeController(vueApp) {
121
+ if (!vueApp || typeof vueApp !== "object") {
122
+ return null;
123
+ }
124
+
125
+ const provides = vueApp._context?.provides;
126
+ if (!provides || typeof provides !== "object") {
127
+ return null;
128
+ }
129
+
130
+ const themeController = provides[ThemeSymbol];
131
+ if (
132
+ !themeController ||
133
+ typeof themeController !== "object" ||
134
+ !themeController.global ||
135
+ !themeController.global.name
136
+ ) {
137
+ return null;
138
+ }
139
+
140
+ return themeController;
141
+ }
142
+
143
+ function setVuetifyThemeName(themeController, themeName) {
144
+ if (
145
+ !themeController ||
146
+ typeof themeController !== "object" ||
147
+ !themeController.global ||
148
+ !themeController.global.name
149
+ ) {
150
+ return false;
151
+ }
152
+
153
+ const normalizedThemeName = themeName === THEME_PREFERENCE_DARK ? THEME_PREFERENCE_DARK : THEME_PREFERENCE_LIGHT;
154
+ if (themeController.global.name.value === normalizedThemeName) {
155
+ return false;
156
+ }
157
+ themeController.global.name.value = normalizedThemeName;
158
+ return true;
159
+ }
160
+
161
+ function normalizeHexColor(value = "") {
162
+ const normalized = String(value || "").trim();
163
+ if (!HEX_COLOR_PATTERN.test(normalized)) {
164
+ return "";
165
+ }
166
+ return normalized.toUpperCase();
167
+ }
168
+
169
+ function hexColorToRgb(value = "") {
170
+ const normalized = normalizeHexColor(value);
171
+ if (!normalized) {
172
+ return "";
173
+ }
174
+
175
+ const red = Number.parseInt(normalized.slice(1, 3), 16);
176
+ const green = Number.parseInt(normalized.slice(3, 5), 16);
177
+ const blue = Number.parseInt(normalized.slice(5, 7), 16);
178
+ return `${red},${green},${blue}`;
179
+ }
180
+
181
+ function resolveVuetifyThemeDefinitions(themeController) {
182
+ if (!themeController || typeof themeController !== "object") {
183
+ return null;
184
+ }
185
+ const themes = themeController.themes?.value;
186
+ if (!themes || typeof themes !== "object") {
187
+ return null;
188
+ }
189
+ return themes;
190
+ }
191
+
192
+ function normalizeThemeColors(colors) {
193
+ const source = colors && typeof colors === "object" ? colors : {};
194
+ const normalized = {};
195
+ for (const [key, value] of Object.entries(source)) {
196
+ normalized[String(key)] = String(value);
197
+ }
198
+ return normalized;
199
+ }
200
+
201
+ function normalizeWorkspaceBaseThemeName(themeName = "") {
202
+ const normalized = String(themeName || "").trim().toLowerCase();
203
+ if (normalized === WORKSPACE_THEME_NAME_LIGHT) {
204
+ return THEME_PREFERENCE_LIGHT;
205
+ }
206
+ if (normalized === WORKSPACE_THEME_NAME_DARK) {
207
+ return THEME_PREFERENCE_DARK;
208
+ }
209
+ if (normalized === THEME_PREFERENCE_DARK) {
210
+ return THEME_PREFERENCE_DARK;
211
+ }
212
+ return THEME_PREFERENCE_LIGHT;
213
+ }
214
+
215
+ function areThemeColorsEqual(leftColors = {}, rightColors = {}) {
216
+ const leftEntries = Object.entries(leftColors);
217
+ const rightEntries = Object.entries(rightColors);
218
+ if (leftEntries.length !== rightEntries.length) {
219
+ return false;
220
+ }
221
+
222
+ for (const [key, value] of leftEntries) {
223
+ if (!Object.hasOwn(rightColors, key)) {
224
+ return false;
225
+ }
226
+ if (String(rightColors[key]) !== String(value)) {
227
+ return false;
228
+ }
229
+ }
230
+ return true;
231
+ }
232
+
233
+ function composeWorkspaceThemeDefinition(baseThemeDefinition, palette) {
234
+ const baseTheme = baseThemeDefinition && typeof baseThemeDefinition === "object" ? baseThemeDefinition : {};
235
+ const baseColors = normalizeThemeColors(baseTheme.colors);
236
+ return {
237
+ ...baseTheme,
238
+ colors: {
239
+ ...baseColors,
240
+ primary: palette.color,
241
+ secondary: palette.secondaryColor,
242
+ surface: palette.surfaceColor,
243
+ "surface-variant": palette.surfaceVariantColor
244
+ }
245
+ };
246
+ }
247
+
248
+ function upsertThemeDefinition(themeDefinitions, themeName, nextDefinition) {
249
+ const currentDefinition =
250
+ themeDefinitions[themeName] && typeof themeDefinitions[themeName] === "object" ? themeDefinitions[themeName] : null;
251
+ const currentColors = normalizeThemeColors(currentDefinition?.colors);
252
+ const nextColors = normalizeThemeColors(nextDefinition?.colors);
253
+ const sameDarkFlag = Boolean(currentDefinition?.dark) === Boolean(nextDefinition?.dark);
254
+ if (sameDarkFlag && areThemeColorsEqual(currentColors, nextColors)) {
255
+ return false;
256
+ }
257
+ themeDefinitions[themeName] = nextDefinition;
258
+ return true;
259
+ }
260
+
261
+ function setVuetifyPrimaryColorOverride(themeController, themeInput = null) {
262
+ if (
263
+ !themeController ||
264
+ typeof themeController !== "object" ||
265
+ !themeController.global ||
266
+ !themeController.global.name
267
+ ) {
268
+ return false;
269
+ }
270
+
271
+ const themeDefinitions = resolveVuetifyThemeDefinitions(themeController);
272
+ if (!themeDefinitions) {
273
+ return false;
274
+ }
275
+
276
+ const currentThemeName = String(themeController.global.name.value || "").trim();
277
+ const normalizedBaseThemeName = normalizeWorkspaceBaseThemeName(currentThemeName);
278
+ const normalizedThemeName =
279
+ normalizedBaseThemeName === THEME_PREFERENCE_DARK ? THEME_PREFERENCE_DARK : THEME_PREFERENCE_LIGHT;
280
+ const source = themeInput && typeof themeInput === "object" ? themeInput : null;
281
+
282
+ if (!source) {
283
+ if (currentThemeName === normalizedThemeName) {
284
+ return false;
285
+ }
286
+ themeController.global.name.value = normalizedThemeName;
287
+ return true;
288
+ }
289
+
290
+ const baseLightTheme =
291
+ themeDefinitions[THEME_PREFERENCE_LIGHT] && typeof themeDefinitions[THEME_PREFERENCE_LIGHT] === "object"
292
+ ? themeDefinitions[THEME_PREFERENCE_LIGHT]
293
+ : null;
294
+ const baseDarkTheme =
295
+ themeDefinitions[THEME_PREFERENCE_DARK] && typeof themeDefinitions[THEME_PREFERENCE_DARK] === "object"
296
+ ? themeDefinitions[THEME_PREFERENCE_DARK]
297
+ : null;
298
+ if (!baseLightTheme || !baseDarkTheme) {
299
+ return false;
300
+ }
301
+
302
+ const lightPalette = resolveWorkspaceThemePalette(source, { mode: THEME_PREFERENCE_LIGHT });
303
+ const darkPalette = resolveWorkspaceThemePalette(source, { mode: THEME_PREFERENCE_DARK });
304
+ const nextLightTheme = composeWorkspaceThemeDefinition(baseLightTheme, lightPalette);
305
+ const nextDarkTheme = composeWorkspaceThemeDefinition(baseDarkTheme, darkPalette);
306
+ const nextThemeName =
307
+ normalizedThemeName === THEME_PREFERENCE_DARK ? WORKSPACE_THEME_NAME_DARK : WORKSPACE_THEME_NAME_LIGHT;
308
+
309
+ let changed = false;
310
+ changed = upsertThemeDefinition(themeDefinitions, WORKSPACE_THEME_NAME_LIGHT, nextLightTheme) || changed;
311
+ changed = upsertThemeDefinition(themeDefinitions, WORKSPACE_THEME_NAME_DARK, nextDarkTheme) || changed;
312
+ if (themeController.global.name.value !== nextThemeName) {
313
+ themeController.global.name.value = nextThemeName;
314
+ changed = true;
315
+ }
316
+
317
+ return changed;
318
+ }
319
+
320
+ export {
321
+ hexColorToRgb,
322
+ normalizeThemePreference,
323
+ persistBootstrapThemePreference,
324
+ persistThemePreference,
325
+ readPersistedThemePreference,
326
+ resolveBootstrapThemePreference,
327
+ resolveThemeNameForPreference,
328
+ resolveBootstrapThemeName,
329
+ resolveVuetifyThemeController,
330
+ setVuetifyPrimaryColorOverride,
331
+ setVuetifyThemeName
332
+ };
@@ -0,0 +1,207 @@
1
+ import { unref } from "vue";
2
+ import { resolveLinkPath } from "@jskit-ai/kernel/shared";
3
+ import { normalizeSurfaceId } from "@jskit-ai/kernel/shared/surface/registry";
4
+ import {
5
+ useWebPlacementContext,
6
+ resolveRuntimePathname,
7
+ resolveSurfaceDefinitionFromPlacementContext,
8
+ resolveSurfaceIdFromPlacementPathname,
9
+ resolveSurfaceRootPathFromPlacementContext
10
+ } from "@jskit-ai/shell-web/client/placement";
11
+ import {
12
+ resolveWorkspaceSurfaceIdFromPlacementPathname,
13
+ resolveSurfaceWorkspacePathFromPlacementContext,
14
+ extractWorkspaceSlugFromSurfacePathname
15
+ } from "./workspaceSurfacePaths.js";
16
+ import { surfaceRequiresWorkspaceFromPlacementContext } from "./workspaceSurfaceContext.js";
17
+ import { parseWorkspacePathname } from "@jskit-ai/workspaces-core/shared/support/workspacePathModel";
18
+
19
+ function resolveSurfaceBasePath(context = null, surface = "") {
20
+ const normalizedSurface = normalizeSurfaceId(surface);
21
+ if (!normalizedSurface) {
22
+ return "";
23
+ }
24
+
25
+ if (!resolveSurfaceDefinitionFromPlacementContext(context, normalizedSurface)) {
26
+ return "";
27
+ }
28
+
29
+ return resolveSurfaceRootPathFromPlacementContext(context, normalizedSurface);
30
+ }
31
+
32
+ function resolveWorkspaceSlugFromContextOrPath({
33
+ context = null,
34
+ surface = "",
35
+ workspaceSlug = "",
36
+ pathname = ""
37
+ } = {}) {
38
+ const explicitWorkspaceSlug = String(workspaceSlug || "").trim();
39
+ if (explicitWorkspaceSlug) {
40
+ return explicitWorkspaceSlug;
41
+ }
42
+
43
+ const workspaceSlugFromContext = String(context?.workspace?.slug || "").trim();
44
+ if (workspaceSlugFromContext) {
45
+ return workspaceSlugFromContext;
46
+ }
47
+
48
+ const currentPathname = resolveRuntimePathname(pathname);
49
+ const workspaceSlugFromPath = String(parseWorkspacePathname(currentPathname)?.workspaceSlug || "").trim();
50
+ if (workspaceSlugFromPath) {
51
+ return workspaceSlugFromPath;
52
+ }
53
+
54
+ const normalizedSurface = normalizeSurfaceId(surface);
55
+ const workspaceSurfaceId = resolveWorkspaceSurfaceIdFromPlacementPathname(context, currentPathname);
56
+ const surfaceIdFromPath = workspaceSurfaceId || resolveSurfaceIdFromPlacementPathname(context, currentPathname);
57
+ const activeSurfaceId = normalizeSurfaceId(surfaceIdFromPath || normalizedSurface);
58
+ if (!activeSurfaceId) {
59
+ return "";
60
+ }
61
+
62
+ return String(extractWorkspaceSlugFromSurfacePathname(context, activeSurfaceId, currentPathname) || "").trim();
63
+ }
64
+
65
+ function resolveWorkspaceBasePath(context = null, surface = "", workspaceSlug = "") {
66
+ const normalizedSurface = normalizeSurfaceId(surface);
67
+ const normalizedWorkspaceSlug = String(workspaceSlug || "").trim();
68
+ if (!normalizedSurface || !normalizedWorkspaceSlug) {
69
+ return "";
70
+ }
71
+
72
+ if (!resolveSurfaceDefinitionFromPlacementContext(context, normalizedSurface)) {
73
+ return "";
74
+ }
75
+
76
+ if (!surfaceRequiresWorkspaceFromPlacementContext(context, normalizedSurface)) {
77
+ return resolveSurfaceBasePath(context, normalizedSurface);
78
+ }
79
+
80
+ return resolveSurfaceWorkspacePathFromPlacementContext(context, normalizedSurface, normalizedWorkspaceSlug, "/");
81
+ }
82
+
83
+ function resolveWorkspaceShellLinkPath({
84
+ context = null,
85
+ surface = "",
86
+ mode = "auto",
87
+ explicitTo = "",
88
+ relativePath = "/",
89
+ workspaceRelativePath = "",
90
+ surfaceRelativePath = "",
91
+ workspaceSlug = "",
92
+ pathname = ""
93
+ } = {}) {
94
+ const explicitTarget = String(explicitTo || "").trim();
95
+ if (explicitTarget) {
96
+ return explicitTarget;
97
+ }
98
+
99
+ const normalizedSurface = normalizeSurfaceId(surface);
100
+ const normalizedMode = String(mode || "auto").trim().toLowerCase();
101
+ const hasSurfaceDefinition = Boolean(
102
+ normalizedSurface && resolveSurfaceDefinitionFromPlacementContext(context, normalizedSurface)
103
+ );
104
+ if (!hasSurfaceDefinition) {
105
+ return "";
106
+ }
107
+
108
+ const resolvedWorkspaceSlug = resolveWorkspaceSlugFromContextOrPath({
109
+ context,
110
+ surface: normalizedSurface,
111
+ workspaceSlug,
112
+ pathname
113
+ });
114
+
115
+ const nextWorkspaceRelativePath = String(workspaceRelativePath || "").trim() || String(relativePath || "").trim() || "/";
116
+ const nextSurfaceRelativePath = String(surfaceRelativePath || "").trim() || String(relativePath || "").trim() || "/";
117
+ const nextSurfaceBasePath = resolveSurfaceBasePath(context, normalizedSurface);
118
+
119
+ if (normalizedMode === "surface") {
120
+ return resolveLinkPath(nextSurfaceBasePath, nextSurfaceRelativePath);
121
+ }
122
+
123
+ if (normalizedMode === "workspace") {
124
+ if (!surfaceRequiresWorkspaceFromPlacementContext(context, normalizedSurface)) {
125
+ return resolveLinkPath(nextSurfaceBasePath, nextSurfaceRelativePath);
126
+ }
127
+ if (!resolvedWorkspaceSlug) {
128
+ return "";
129
+ }
130
+ const workspaceBasePath = resolveWorkspaceBasePath(context, normalizedSurface, resolvedWorkspaceSlug);
131
+ if (!workspaceBasePath) {
132
+ return "";
133
+ }
134
+ return resolveLinkPath(
135
+ workspaceBasePath,
136
+ nextWorkspaceRelativePath
137
+ );
138
+ }
139
+
140
+ if (surfaceRequiresWorkspaceFromPlacementContext(context, normalizedSurface)) {
141
+ if (!resolvedWorkspaceSlug) {
142
+ return "";
143
+ }
144
+ const workspaceBasePath = resolveWorkspaceBasePath(context, normalizedSurface, resolvedWorkspaceSlug);
145
+ if (!workspaceBasePath) {
146
+ return "";
147
+ }
148
+ return resolveLinkPath(
149
+ workspaceBasePath,
150
+ nextWorkspaceRelativePath
151
+ );
152
+ }
153
+
154
+ return resolveLinkPath(nextSurfaceBasePath, nextSurfaceRelativePath);
155
+ }
156
+
157
+ function useWorkspaceLinkResolver({ surface = "", workspaceSlug = "", pathname = "" } = {}) {
158
+ const { context: placementContext } = useWebPlacementContext();
159
+
160
+ function resolve(relativePath = "/", options = {}) {
161
+ return resolveWorkspaceShellLinkPath({
162
+ context: placementContext.value,
163
+ surface: String(unref(options.surface ?? surface) || ""),
164
+ workspaceSlug: String(unref(options.workspaceSlug ?? workspaceSlug) || ""),
165
+ pathname: String(unref(options.pathname ?? pathname) || ""),
166
+ mode: String(options.mode || "auto"),
167
+ explicitTo: options.explicitTo,
168
+ relativePath,
169
+ workspaceRelativePath: options.workspaceRelativePath,
170
+ surfaceRelativePath: options.surfaceRelativePath
171
+ });
172
+ }
173
+
174
+ function toSurface(relativePath = "/", options = {}) {
175
+ return resolve(relativePath, {
176
+ ...options,
177
+ mode: "surface"
178
+ });
179
+ }
180
+
181
+ function toWorkspace(relativePath = "/", options = {}) {
182
+ return resolve(relativePath, {
183
+ ...options,
184
+ mode: "workspace"
185
+ });
186
+ }
187
+
188
+ function toAuto(relativePath = "/", options = {}) {
189
+ return resolve(relativePath, {
190
+ ...options,
191
+ mode: "auto"
192
+ });
193
+ }
194
+
195
+ return Object.freeze({
196
+ resolve,
197
+ toSurface,
198
+ toWorkspace,
199
+ toAuto
200
+ });
201
+ }
202
+
203
+ export {
204
+ resolveWorkspaceSlugFromContextOrPath,
205
+ resolveWorkspaceShellLinkPath,
206
+ useWorkspaceLinkResolver
207
+ };
@@ -0,0 +1,82 @@
1
+ import { normalizeSurfaceId } from "@jskit-ai/kernel/shared/surface";
2
+ import {
3
+ readPlacementSurfaceConfig,
4
+ resolveSurfaceDefinitionFromPlacementContext
5
+ } from "@jskit-ai/shell-web/client/placement";
6
+
7
+ function listWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig = null) {
8
+ return listSurfaceIdsFromSurfaceConfig(surfaceConfig, {
9
+ requiresWorkspace: true
10
+ });
11
+ }
12
+
13
+ function listNonWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig = null) {
14
+ return listSurfaceIdsFromSurfaceConfig(surfaceConfig, {
15
+ requiresWorkspace: false
16
+ });
17
+ }
18
+
19
+ function listSurfaceIdsFromSurfaceConfig(surfaceConfig = null, { requiresWorkspace = null } = {}) {
20
+ const source = surfaceConfig && typeof surfaceConfig === "object" ? surfaceConfig : {};
21
+ const enabledSurfaceIds = Array.isArray(source.enabledSurfaceIds) ? source.enabledSurfaceIds : [];
22
+ const surfacesById = source.surfacesById && typeof source.surfacesById === "object" ? source.surfacesById : {};
23
+
24
+ const result = [];
25
+ for (const candidate of enabledSurfaceIds) {
26
+ const surfaceId = normalizeSurfaceId(candidate);
27
+ if (!surfaceId) {
28
+ continue;
29
+ }
30
+ const surfaceRequiresWorkspace = surfacesById[surfaceId]?.requiresWorkspace === true;
31
+ if (requiresWorkspace === true && !surfaceRequiresWorkspace) {
32
+ continue;
33
+ }
34
+ if (requiresWorkspace === false && surfaceRequiresWorkspace) {
35
+ continue;
36
+ }
37
+ result.push(surfaceId);
38
+ }
39
+ return result;
40
+ }
41
+
42
+ function surfaceRequiresWorkspaceFromPlacementContext(contextValue = null, surfaceId = "") {
43
+ return Boolean(resolveSurfaceDefinitionFromPlacementContext(contextValue, surfaceId)?.requiresWorkspace);
44
+ }
45
+
46
+ function firstAlternativeSurfaceId(surfaceIds = [], excludeSurfaceId = "") {
47
+ const normalizedExcludeSurfaceId = normalizeSurfaceId(excludeSurfaceId);
48
+ for (const candidate of Array.isArray(surfaceIds) ? surfaceIds : []) {
49
+ const surfaceId = normalizeSurfaceId(candidate);
50
+ if (!surfaceId || surfaceId === normalizedExcludeSurfaceId) {
51
+ continue;
52
+ }
53
+ return surfaceId;
54
+ }
55
+ return "";
56
+ }
57
+
58
+ function resolveSurfaceSwitchTargetsFromPlacementContext(contextValue = null, surfaceId = "") {
59
+ const surfaceConfig = readPlacementSurfaceConfig(contextValue);
60
+ const currentSurface = resolveSurfaceDefinitionFromPlacementContext(contextValue, surfaceId);
61
+ const currentSurfaceId = normalizeSurfaceId(currentSurface?.id);
62
+ const defaultSurfaceId = normalizeSurfaceId(surfaceConfig.defaultSurfaceId);
63
+ const defaultSurface = defaultSurfaceId ? surfaceConfig.surfacesById[defaultSurfaceId] || null : null;
64
+ const workspaceSurfaceIds = listWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig);
65
+ const nonWorkspaceSurfaceIds = listNonWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig);
66
+
67
+ return Object.freeze({
68
+ surfaceConfig,
69
+ currentSurfaceId,
70
+ currentSurface,
71
+ defaultSurfaceId,
72
+ defaultSurface,
73
+ workspaceSurfaceId: firstAlternativeSurfaceId(workspaceSurfaceIds, currentSurfaceId),
74
+ nonWorkspaceSurfaceId: firstAlternativeSurfaceId(nonWorkspaceSurfaceIds, currentSurfaceId)
75
+ });
76
+ }
77
+
78
+ export {
79
+ listWorkspaceSurfaceIdsFromSurfaceConfig,
80
+ surfaceRequiresWorkspaceFromPlacementContext,
81
+ resolveSurfaceSwitchTargetsFromPlacementContext
82
+ };