@sanity/workbench 0.1.0-alpha.6 → 0.1.0-alpha.7
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/dist/{log.js → _chunks-es/index.js} +1 -1
- package/dist/_chunks-es/index.js.map +1 -0
- package/dist/_internal.d.ts +13 -6
- package/dist/_internal.js +19 -3
- package/dist/_internal.js.map +1 -1
- package/dist/core.d.ts +906 -0
- package/dist/core.js +642 -0
- package/dist/core.js.map +1 -0
- package/package.json +10 -4
- package/src/_exports/core.ts +1 -0
- package/src/_internal/index.ts +2 -1
- package/src/_internal/render.test.ts +56 -1
- package/src/_internal/render.ts +51 -24
- package/src/core/__tests__/__fixtures__.ts +248 -0
- package/src/core/applications/application-list.test.ts +222 -0
- package/src/core/applications/application-list.ts +103 -0
- package/src/core/applications/application.ts +78 -0
- package/src/core/applications/local-application.test.ts +93 -0
- package/src/core/applications/local-application.ts +52 -0
- package/src/core/canvases.test.ts +38 -0
- package/src/core/canvases.ts +81 -0
- package/src/core/config.ts +34 -0
- package/src/core/index.ts +12 -0
- package/src/core/media-libraries.test.ts +38 -0
- package/src/core/media-libraries.ts +83 -0
- package/src/core/organizations.test.ts +134 -0
- package/src/core/organizations.ts +115 -0
- package/src/core/projects.test.ts +248 -0
- package/src/core/projects.ts +114 -0
- package/src/core/shared/urls.test.ts +182 -0
- package/src/core/shared/urls.ts +128 -0
- package/src/core/user-applications/core-app.test.ts +151 -0
- package/src/core/user-applications/core-app.ts +57 -0
- package/src/core/user-applications/studio.test.ts +928 -0
- package/src/core/user-applications/studio.ts +656 -0
- package/src/core/user-applications/user-application.test.ts +126 -0
- package/src/core/user-applications/user-application.ts +76 -0
- package/src/vite-env.d.ts +8 -0
- package/dist/log.d.ts +0 -48
- package/dist/log.js.map +0 -1
- package/src/_exports/log.ts +0 -1
- /package/src/{log → core/log}/index.test.ts +0 -0
- /package/src/{log → core/log}/index.ts +0 -0
|
@@ -0,0 +1,928 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
StudioApplication as StudioApplicationApiResponse,
|
|
3
|
+
// eslint-disable-next-line no-restricted-imports
|
|
4
|
+
StudioResource as ProtocolStudioResource,
|
|
5
|
+
} from "@sanity/message-protocol";
|
|
6
|
+
import { afterEach, describe, expect, expectTypeOf, vi, it } from "vitest";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
10
|
+
PROJECTS,
|
|
11
|
+
SINGLE_WORKSPACE_STUDIO_DATA,
|
|
12
|
+
} from "../__tests__/__fixtures__";
|
|
13
|
+
import type { ProjectId } from "../projects";
|
|
14
|
+
import { StudioApplication, StudioWorkspace } from "./studio";
|
|
15
|
+
import { brandUserApplicationId } from "./user-application";
|
|
16
|
+
|
|
17
|
+
describe("StudioApplication", () => {
|
|
18
|
+
afterEach(() => {
|
|
19
|
+
vi.unstubAllEnvs();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const setup = (application?: StudioApplicationApiResponse) =>
|
|
23
|
+
new StudioApplication(
|
|
24
|
+
{
|
|
25
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
26
|
+
...application,
|
|
27
|
+
manifest: null,
|
|
28
|
+
},
|
|
29
|
+
PROJECTS,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
it("should have a list of studio workspaces", () => {
|
|
33
|
+
const studio = setup();
|
|
34
|
+
|
|
35
|
+
expect(studio.workspaces).toHaveLength(8);
|
|
36
|
+
expect(studio.workspaces[0]).toBeInstanceOf(StudioWorkspace);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should supply me a default workspace if the application has no manifest", () => {
|
|
40
|
+
const studio = setup({
|
|
41
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
42
|
+
manifestData: null,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(studio.workspaces).toHaveLength(1);
|
|
46
|
+
expectTypeOf(studio.workspaces).toEqualTypeOf<readonly StudioWorkspace[]>();
|
|
47
|
+
expect(studio.workspaces[0]).toBeInstanceOf(StudioWorkspace);
|
|
48
|
+
|
|
49
|
+
// @ts-expect-error - workspace is protected but we want to test the snapshot for default values
|
|
50
|
+
expect(studio.workspaces[0].workspace).toMatchInlineSnapshot(`
|
|
51
|
+
{
|
|
52
|
+
"basePath": "/",
|
|
53
|
+
"name": "default",
|
|
54
|
+
"projectId": "hzao7xsp",
|
|
55
|
+
"title": "Default",
|
|
56
|
+
}
|
|
57
|
+
`);
|
|
58
|
+
expect(studio.workspaces[0].href).toMatchInlineSnapshot(
|
|
59
|
+
`"/studio/75affa24c862a372764ceb40/default"`,
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should supply me a default workspace if the application has a manifest but no workspaces", () => {
|
|
64
|
+
const studio = setup({
|
|
65
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
66
|
+
manifestData: {
|
|
67
|
+
value: {
|
|
68
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
69
|
+
workspaces: [],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
expect(studio.workspaces).toHaveLength(1);
|
|
75
|
+
expectTypeOf(studio.workspaces).toEqualTypeOf<readonly StudioWorkspace[]>();
|
|
76
|
+
expect(studio.workspaces[0]).toBeInstanceOf(StudioWorkspace);
|
|
77
|
+
|
|
78
|
+
// @ts-expect-error - workspace is protected but we want to test the snapshot for default values
|
|
79
|
+
expect(studio.workspaces[0].workspace).toMatchInlineSnapshot(`
|
|
80
|
+
{
|
|
81
|
+
"basePath": "/",
|
|
82
|
+
"name": "default",
|
|
83
|
+
"projectId": "hzao7xsp",
|
|
84
|
+
"title": "Default",
|
|
85
|
+
}
|
|
86
|
+
`);
|
|
87
|
+
expect(studio.workspaces[0].href).toMatchInlineSnapshot(
|
|
88
|
+
`"/studio/75affa24c862a372764ceb40/default"`,
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should have type of studio", () => {
|
|
93
|
+
const studio = setup();
|
|
94
|
+
|
|
95
|
+
expect(studio.type).toBe("studio");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should use the first workspace title as the title if it does not have multiple workspaces", () => {
|
|
99
|
+
const studio = setup();
|
|
100
|
+
|
|
101
|
+
expect(studio.title).toBe(studio.workspaces[0].title);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should use the project display name as the title and urlType is internal", () => {
|
|
105
|
+
const studio = setup({
|
|
106
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
107
|
+
urlType: "internal",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
expect(studio.title).toBe("Customer 360");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should use the application title when set, regardless of workspace count or urlType", () => {
|
|
114
|
+
const customTitle = "My Custom Studio";
|
|
115
|
+
|
|
116
|
+
// Single workspace, internal
|
|
117
|
+
const singleInternal = setup({
|
|
118
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
119
|
+
title: customTitle,
|
|
120
|
+
});
|
|
121
|
+
expect(singleInternal.title).toBe(customTitle);
|
|
122
|
+
|
|
123
|
+
// Multiple workspaces, external
|
|
124
|
+
const multiExternal = setup({
|
|
125
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
126
|
+
title: customTitle,
|
|
127
|
+
});
|
|
128
|
+
expect(multiExternal.title).toBe(customTitle);
|
|
129
|
+
|
|
130
|
+
// Multiple workspaces, internal (would normally fall back to project.displayName)
|
|
131
|
+
const multiInternal = setup({
|
|
132
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
133
|
+
urlType: "internal",
|
|
134
|
+
title: customTitle,
|
|
135
|
+
});
|
|
136
|
+
expect(multiInternal.title).toBe(customTitle);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should fall back to workspace/project title when application title is null", () => {
|
|
140
|
+
// External with multiple workspaces and no application title -> first workspace title
|
|
141
|
+
const externalStudio = setup({
|
|
142
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
143
|
+
title: null,
|
|
144
|
+
});
|
|
145
|
+
expect(externalStudio.title).toBe(externalStudio.workspaces[0].title);
|
|
146
|
+
|
|
147
|
+
// Internal with multiple workspaces and no application title -> project displayName
|
|
148
|
+
const internalStudio = setup({
|
|
149
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
150
|
+
urlType: "internal",
|
|
151
|
+
title: null,
|
|
152
|
+
});
|
|
153
|
+
expect(internalStudio.title).toBe("Customer 360");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("should return the hostname as the subtitle", () => {
|
|
157
|
+
vi.stubEnv("VITE_SANITY_ENV", "staging");
|
|
158
|
+
vi.stubEnv("VITE_SANITY_DOMAIN", "sanity.work");
|
|
159
|
+
const studio = setup();
|
|
160
|
+
expect(studio.subtitle).toBe("360.sanity.build");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("should allow you to get attributes from the application", () => {
|
|
164
|
+
const studio = setup();
|
|
165
|
+
|
|
166
|
+
expect(studio.get("title")).toBe(null);
|
|
167
|
+
expect(studio.get("urlType")).toBe("external");
|
|
168
|
+
expectTypeOf(studio.get("urlType")).toEqualTypeOf<
|
|
169
|
+
"internal" | "external"
|
|
170
|
+
>();
|
|
171
|
+
expect(studio.get("appHost")).toBe("https://360.sanity.build");
|
|
172
|
+
expectTypeOf(studio.get("appHost")).toEqualTypeOf<string>();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should throw when accessing a non-existent attribute", () => {
|
|
176
|
+
const studio = setup();
|
|
177
|
+
expect(() =>
|
|
178
|
+
// @ts-expect-error - testing invalid attribute
|
|
179
|
+
studio.get("nonExistent"),
|
|
180
|
+
).toThrow(
|
|
181
|
+
`Attribute nonExistent does not exist on studio ${MULTIPLE_WORKSPACE_STUDIO_DATA.id}`,
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should throw when project is not found for the application", () => {
|
|
186
|
+
expect(
|
|
187
|
+
() =>
|
|
188
|
+
new StudioApplication(
|
|
189
|
+
{
|
|
190
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
191
|
+
projectId: "non-existing-project",
|
|
192
|
+
},
|
|
193
|
+
PROJECTS,
|
|
194
|
+
),
|
|
195
|
+
).toThrow(
|
|
196
|
+
`Project not found for application ${SINGLE_WORKSPACE_STUDIO_DATA.id}`,
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should fall back to deployment manifest workspaces when main manifest has no workspaces", () => {
|
|
201
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
202
|
+
|
|
203
|
+
const studio = setup({
|
|
204
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
205
|
+
manifestData: {
|
|
206
|
+
value: {
|
|
207
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
208
|
+
workspaces: [],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
activeDeployment: {
|
|
212
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment!,
|
|
213
|
+
manifest: {
|
|
214
|
+
workspaces: [
|
|
215
|
+
{
|
|
216
|
+
name: "from-deployment",
|
|
217
|
+
title: "From Deployment",
|
|
218
|
+
basePath: "/from-deployment",
|
|
219
|
+
projectId: "c16r74n4",
|
|
220
|
+
dataset: "production",
|
|
221
|
+
schemaDescriptorId: "test.json",
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(studio.workspaces).toHaveLength(1);
|
|
229
|
+
expect(studio.workspaces[0].title).toBe("From Deployment");
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("should throw an error if the studio application is converted to a protocol resource", () => {
|
|
233
|
+
const studio = setup();
|
|
234
|
+
expect(() => studio.toProtocolResource()).toThrow(
|
|
235
|
+
"Studio application resources cannot be converted to protocol resources",
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("should return a value for hasManifest", () => {
|
|
240
|
+
const studio = setup();
|
|
241
|
+
expect(studio.hasManifest).toBe(true);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("should return a value for hasSchema", () => {
|
|
245
|
+
const studio = setup();
|
|
246
|
+
expect(studio.hasSchema).toBe(true);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("should return true for hasSchema, even though the user does not have access to any workspaces", () => {
|
|
250
|
+
const studio = setup({
|
|
251
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
252
|
+
manifestData: {
|
|
253
|
+
value: {
|
|
254
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
255
|
+
workspaces: [
|
|
256
|
+
{
|
|
257
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value.workspaces[0],
|
|
258
|
+
projectId: "non-existing-project",
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
expect(studio.hasSchema).toBe(true);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("should return false for hasSchema, without any workspaces", () => {
|
|
269
|
+
const studio = setup({
|
|
270
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
271
|
+
manifestData: {
|
|
272
|
+
value: {
|
|
273
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
274
|
+
workspaces: [],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(studio.hasSchema).toBe(false);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
describe("version", () => {
|
|
283
|
+
it("should return the activeDeployment version if the studio is internal", () => {
|
|
284
|
+
const version = "4.9.0";
|
|
285
|
+
|
|
286
|
+
const studio = setup({
|
|
287
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
288
|
+
activeDeployment: {
|
|
289
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
290
|
+
version,
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(studio.version).toBe(version);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should return the manifest studioVersion if the studio is external", () => {
|
|
298
|
+
const studioVersion = "4.9.0";
|
|
299
|
+
|
|
300
|
+
const studio = setup({
|
|
301
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
302
|
+
manifestData: {
|
|
303
|
+
value: {
|
|
304
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
305
|
+
version: 3,
|
|
306
|
+
studioVersion,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
expect(studio.version).toBe(studioVersion);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("should return the deployment-manifest bundleVersion if the studio has no version in the manifest", () => {
|
|
315
|
+
const bundleVersion = "4.9.0";
|
|
316
|
+
|
|
317
|
+
const studio = setup({
|
|
318
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
319
|
+
manifestData: {
|
|
320
|
+
value: {
|
|
321
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
322
|
+
version: 2,
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
activeDeployment: {
|
|
326
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
327
|
+
manifest: {
|
|
328
|
+
bundleVersion,
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
config: {},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
expect(studio.version).toBe(bundleVersion);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("should return the live-manifest bundleVersion if the studio is external and the live-manifest version is greater than the manifest version", () => {
|
|
338
|
+
const studioVersion = "4.9.0";
|
|
339
|
+
const bundleVersion = "5.0.0";
|
|
340
|
+
|
|
341
|
+
const studio = setup({
|
|
342
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
343
|
+
activeDeployment: {
|
|
344
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
345
|
+
manifest: {
|
|
346
|
+
bundleVersion,
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
manifestData: {
|
|
350
|
+
value: {
|
|
351
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
352
|
+
version: 3,
|
|
353
|
+
studioVersion,
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
config: {},
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
expect(studio.version).toBe(bundleVersion);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("should return null if the version is not a valid semver", () => {
|
|
363
|
+
const studio = setup({
|
|
364
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
365
|
+
manifestData: {
|
|
366
|
+
value: {
|
|
367
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
368
|
+
version: 3,
|
|
369
|
+
studioVersion: "invalid",
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
expect(studio.version).toBeNull();
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it("should return null if its an external studio and the manifest does not have a studioVersion", () => {
|
|
378
|
+
const studio = setup(MULTIPLE_WORKSPACE_STUDIO_DATA);
|
|
379
|
+
expect(studio.version).toBeNull();
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe("compatability status", () => {
|
|
384
|
+
it('should return "unknown" if the version is unknown or less than the minimum version', () => {
|
|
385
|
+
expect(setup(MULTIPLE_WORKSPACE_STUDIO_DATA).compatibilityStatus).toBe(
|
|
386
|
+
"unknown",
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
expect(
|
|
390
|
+
setup({ ...MULTIPLE_WORKSPACE_STUDIO_DATA, manifest: null })
|
|
391
|
+
.compatibilityStatus,
|
|
392
|
+
).toBe("unknown");
|
|
393
|
+
|
|
394
|
+
// Studio with version below minimum (2.28.0)
|
|
395
|
+
expect(
|
|
396
|
+
setup({
|
|
397
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
398
|
+
activeDeployment: {
|
|
399
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
400
|
+
version: "2.0.0",
|
|
401
|
+
},
|
|
402
|
+
}).compatibilityStatus,
|
|
403
|
+
).toBe("unknown");
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it("should return partially compatible if the schema is missing or the manifest is missing or the issues are not empty", () => {
|
|
407
|
+
expect(
|
|
408
|
+
setup({
|
|
409
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
410
|
+
manifestData: {
|
|
411
|
+
value: {
|
|
412
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
413
|
+
workspaces: [],
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
}).compatibilityStatus,
|
|
417
|
+
).toBe("partially-compatible");
|
|
418
|
+
|
|
419
|
+
expect(
|
|
420
|
+
setup({
|
|
421
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
422
|
+
activeDeployment: {
|
|
423
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
424
|
+
version: "3.70.0", // Below ACTIVITY and FAVORITES (3.88.1)
|
|
425
|
+
},
|
|
426
|
+
}).compatibilityStatus,
|
|
427
|
+
).toBe("partially-compatible");
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it("should return fully compatible if the schema is present, the manifest is present and the issues are empty", () => {
|
|
431
|
+
const studio = setup({
|
|
432
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
433
|
+
activeDeployment: {
|
|
434
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
435
|
+
version: StudioApplication.MinimumStudioVersionWithNoIssues!,
|
|
436
|
+
},
|
|
437
|
+
});
|
|
438
|
+
expect(studio.compatibilityStatus).toBe("fully-compatible");
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
describe("issues", () => {
|
|
443
|
+
it("should return an empty array if the studio is fully compatible", () => {
|
|
444
|
+
const studio = setup({
|
|
445
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
446
|
+
activeDeployment: {
|
|
447
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
448
|
+
version: StudioApplication.MinimumStudioVersionWithNoIssues!,
|
|
449
|
+
},
|
|
450
|
+
});
|
|
451
|
+
expect(studio.issues).toHaveLength(0);
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
it("should return an array of issues if the studio is partially compatible", () => {
|
|
455
|
+
// Version 3.70.0 is below ACTIVITY (3.88.1), FAVORITES (3.88.1), URL_SYNCING (3.75.0), UI_ADJUSTMENT (3.78.1)
|
|
456
|
+
const studio = setup({
|
|
457
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
458
|
+
activeDeployment: {
|
|
459
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
460
|
+
version: "3.70.0",
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const issueIds = studio.issues.map((issue) => issue.id);
|
|
465
|
+
expect(issueIds).toContain("ACTIVITY");
|
|
466
|
+
expect(issueIds).toContain("FAVORITES");
|
|
467
|
+
expect(issueIds).toContain("URL_SYNCING");
|
|
468
|
+
expect(issueIds).toContain("UI_ADJUSTMENT");
|
|
469
|
+
expect(issueIds).not.toContain("CONTENT_MAPPING"); // 3.68.0
|
|
470
|
+
expect(issueIds).not.toContain("LOGIN"); // 2.28.0
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it("should include the manifest issue if the manifest is missing", () => {
|
|
474
|
+
const studio = setup({
|
|
475
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
476
|
+
manifestData: null,
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
const issueIds = studio.issues.map((issue) => issue.id);
|
|
480
|
+
expect(issueIds).toContain("MANIFEST");
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe("MINIMUM_STUDIO_NO_ISSUES_VERSION", () => {
|
|
485
|
+
it("should equal the highest version required by Studio features", () => {
|
|
486
|
+
expect(
|
|
487
|
+
StudioApplication.MinimumStudioVersionWithNoIssues,
|
|
488
|
+
).toMatchInlineSnapshot(`"5.1.0"`);
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
it("should delegate to isAutoRedirecting resolveIsAutoRedirecting", () => {
|
|
493
|
+
const studio = setup({
|
|
494
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
495
|
+
activeDeployment: {
|
|
496
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
497
|
+
version: "4.0.0",
|
|
498
|
+
},
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
expect(studio.isAutoRedirecting).toBe(
|
|
502
|
+
StudioApplication.resolveIsAutoRedirecting(studio),
|
|
503
|
+
);
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
describe("resolveIsAutoRedirecting", () => {
|
|
507
|
+
it("should return false for external studios", () => {
|
|
508
|
+
const studio = setup(MULTIPLE_WORKSPACE_STUDIO_DATA);
|
|
509
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(false);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it("should return false when no version can be determined", () => {
|
|
513
|
+
const studio = setup({
|
|
514
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
515
|
+
activeDeployment: null,
|
|
516
|
+
});
|
|
517
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(false);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it.each(["latest", "next", "stable"])(
|
|
521
|
+
'should return true for auto-updating studios using autoUpdatingVersion of "%s"',
|
|
522
|
+
(autoUpdatingVersion) => {
|
|
523
|
+
const studio = setup({
|
|
524
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
525
|
+
autoUpdatingVersion,
|
|
526
|
+
activeDeployment: {
|
|
527
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
528
|
+
isAutoUpdating: true,
|
|
529
|
+
version: "4.0.0",
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(true);
|
|
533
|
+
},
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
it("should return true if version is higher than MinimumStudioVersion", () => {
|
|
537
|
+
const studio = setup({
|
|
538
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
539
|
+
autoUpdatingVersion: "3.0.0",
|
|
540
|
+
activeDeployment: {
|
|
541
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
542
|
+
isAutoUpdating: true,
|
|
543
|
+
version: "3.0.0",
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(true);
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it("should return false if version is equal or lower than MinimumStudioVersion", () => {
|
|
550
|
+
const studio = setup({
|
|
551
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
552
|
+
autoUpdatingVersion: "2.0.0",
|
|
553
|
+
activeDeployment: {
|
|
554
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
555
|
+
isAutoUpdating: true,
|
|
556
|
+
version: "2.0.0",
|
|
557
|
+
},
|
|
558
|
+
});
|
|
559
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(false);
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it("should fall through to version comparison when autoUpdatingVersion is null and auto-updating", () => {
|
|
563
|
+
const studio = setup({
|
|
564
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
565
|
+
autoUpdatingVersion: null,
|
|
566
|
+
activeDeployment: {
|
|
567
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
568
|
+
isAutoUpdating: true,
|
|
569
|
+
version: "4.0.0",
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(true);
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
it("should use custom version argument when provided for non-auto-updating studios", () => {
|
|
576
|
+
const studio = setup({
|
|
577
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
578
|
+
activeDeployment: {
|
|
579
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.activeDeployment,
|
|
580
|
+
isAutoUpdating: false,
|
|
581
|
+
version: "4.0.0",
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
// Default behavior returns true for version > 3.92.0
|
|
585
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio)).toBe(true);
|
|
586
|
+
// When passing a custom version below 3.92.0, it should return false
|
|
587
|
+
expect(StudioApplication.resolveIsAutoRedirecting(studio, "3.0.0")).toBe(
|
|
588
|
+
false,
|
|
589
|
+
);
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
it("should remove any workspaces where the project is not found", () => {
|
|
594
|
+
// supress the console.warn
|
|
595
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
596
|
+
|
|
597
|
+
const application = {
|
|
598
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
599
|
+
manifestData: {
|
|
600
|
+
value: {
|
|
601
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
602
|
+
workspaces: [
|
|
603
|
+
{
|
|
604
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value
|
|
605
|
+
.workspaces[0],
|
|
606
|
+
projectId: "zvy7mysv",
|
|
607
|
+
},
|
|
608
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value.workspaces.slice(
|
|
609
|
+
1,
|
|
610
|
+
),
|
|
611
|
+
],
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
} satisfies StudioApplicationApiResponse;
|
|
615
|
+
|
|
616
|
+
const studio = setup(application);
|
|
617
|
+
|
|
618
|
+
expect(studio.workspaces).toHaveLength(7);
|
|
619
|
+
studio.workspaces.forEach((workspace) => {
|
|
620
|
+
expect(workspace.title).not.toBe(
|
|
621
|
+
MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value.workspaces[0].title,
|
|
622
|
+
);
|
|
623
|
+
});
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
it("should return a default workspace if the application has workspaces with no matching projects", () => {
|
|
627
|
+
const PROJECT_ID = "zvy7mysv";
|
|
628
|
+
|
|
629
|
+
// supress the console.warn
|
|
630
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
631
|
+
|
|
632
|
+
const application = {
|
|
633
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
634
|
+
manifestData: {
|
|
635
|
+
value: {
|
|
636
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
637
|
+
workspaces: [
|
|
638
|
+
{
|
|
639
|
+
...SINGLE_WORKSPACE_STUDIO_DATA.manifestData.value.workspaces[0],
|
|
640
|
+
projectId: PROJECT_ID,
|
|
641
|
+
},
|
|
642
|
+
],
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
} satisfies StudioApplicationApiResponse;
|
|
646
|
+
|
|
647
|
+
const studio = setup(application);
|
|
648
|
+
|
|
649
|
+
const project = PROJECTS.find(
|
|
650
|
+
(p) => p.id === SINGLE_WORKSPACE_STUDIO_DATA.projectId,
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
expect(PROJECTS.find((p) => p.id === PROJECT_ID)).toBeUndefined();
|
|
654
|
+
expect(studio.workspaces[0].project.id).toBe(project?.id);
|
|
655
|
+
expect(studio.workspaces[0].title).toBe(project?.displayName);
|
|
656
|
+
expect(studio.title).toBe(project?.displayName);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
describe("StudioWorkspace", () => {
|
|
661
|
+
const setup = (application?: StudioApplicationApiResponse) =>
|
|
662
|
+
new StudioApplication(
|
|
663
|
+
{
|
|
664
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
665
|
+
...application,
|
|
666
|
+
},
|
|
667
|
+
PROJECTS,
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
it("should have a type of workspace", () => {
|
|
671
|
+
const workspace = setup().workspaces[1];
|
|
672
|
+
|
|
673
|
+
expect(workspace.type).toBe("workspace");
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
it("should have a href of <studio>/<id>/<workspace-name>", () => {
|
|
677
|
+
const workspace = setup().workspaces[1];
|
|
678
|
+
|
|
679
|
+
expect(workspace.href).toMatchInlineSnapshot(
|
|
680
|
+
`"/studio/75affa24c862a372764ceb40/operations-gateway"`,
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it("should have a name property", () => {
|
|
685
|
+
const workspace = setup().workspaces[1];
|
|
686
|
+
|
|
687
|
+
expect(workspace.get("name")).toBe("operations-gateway");
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
it("should use its own title if it is not the default", () => {
|
|
691
|
+
const workspace = setup().workspaces[1];
|
|
692
|
+
|
|
693
|
+
expect(workspace.title).toBe("Operations Gateway");
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it("should return the workspace subtitle for non-default workspaces", () => {
|
|
697
|
+
const workspace = setup().workspaces[1];
|
|
698
|
+
|
|
699
|
+
expect(workspace.subtitle).toBeUndefined();
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
it("should return the hostname as subtitle for default workspaces with internal appHost", () => {
|
|
703
|
+
vi.stubEnv("VITE_SANITY_ENV", "staging");
|
|
704
|
+
vi.stubEnv("VITE_SANITY_DOMAIN", "sanity.work");
|
|
705
|
+
const workspace = setup({
|
|
706
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
707
|
+
manifestData: null,
|
|
708
|
+
}).workspaces[0];
|
|
709
|
+
|
|
710
|
+
expect(workspace.subtitle).toBe("sanity-home.studio.sanity.work");
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it("should use appHost directly as subtitle when it is a valid URL", () => {
|
|
714
|
+
const workspace = setup({
|
|
715
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
716
|
+
manifestData: null,
|
|
717
|
+
}).workspaces[0];
|
|
718
|
+
|
|
719
|
+
expect(workspace.subtitle).toBe("360.sanity.build");
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
it("should deduplicate basePath when appHost already contains it", () => {
|
|
723
|
+
const workspace = setup({
|
|
724
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA,
|
|
725
|
+
appHost: "https://my-studio.com/admin",
|
|
726
|
+
manifestData: {
|
|
727
|
+
value: {
|
|
728
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value,
|
|
729
|
+
workspaces: [
|
|
730
|
+
{
|
|
731
|
+
...MULTIPLE_WORKSPACE_STUDIO_DATA.manifestData.value
|
|
732
|
+
.workspaces[0],
|
|
733
|
+
basePath: "/admin",
|
|
734
|
+
},
|
|
735
|
+
],
|
|
736
|
+
},
|
|
737
|
+
},
|
|
738
|
+
}).workspaces[0];
|
|
739
|
+
|
|
740
|
+
expect(workspace.url.pathname).toBe("/admin");
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
it("should allow you to get attributes from the application", () => {
|
|
744
|
+
const workspace = setup().workspaces[1];
|
|
745
|
+
|
|
746
|
+
expect(workspace.get("basePath")).toBe("/operations-gateway");
|
|
747
|
+
expectTypeOf(workspace.get("basePath")).toEqualTypeOf<string>();
|
|
748
|
+
expect(workspace.get("projectId")).toBe("hzao7xsp");
|
|
749
|
+
expectTypeOf(workspace.get("projectId")).toEqualTypeOf<ProjectId>();
|
|
750
|
+
expect(workspace.get("dataset")).toBe("production");
|
|
751
|
+
expectTypeOf(workspace.get("dataset")).toEqualTypeOf<string | undefined>();
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
describe("single workspace studio", () => {
|
|
755
|
+
it("should use the title of the workspace if the parent application has a manifest", () => {
|
|
756
|
+
const workspace = setup(SINGLE_WORKSPACE_STUDIO_DATA).workspaces[0];
|
|
757
|
+
|
|
758
|
+
expect(workspace.title).toBe("Sanity Home");
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
it("should use the hostname of the project display name if the parent application does not have a manifest", () => {
|
|
762
|
+
const workspace = setup({
|
|
763
|
+
...SINGLE_WORKSPACE_STUDIO_DATA,
|
|
764
|
+
manifestData: null,
|
|
765
|
+
}).workspaces[0];
|
|
766
|
+
|
|
767
|
+
expect(workspace.title).toBe("Sanity Home");
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it("should have a href of <studio>/<id>/<workspace-name>", () => {
|
|
771
|
+
const workspace = setup(SINGLE_WORKSPACE_STUDIO_DATA).workspaces[0];
|
|
772
|
+
expect(workspace.href).toMatchInlineSnapshot(
|
|
773
|
+
`"/studio/0092b48439cd2aa19de05c2c/default"`,
|
|
774
|
+
);
|
|
775
|
+
});
|
|
776
|
+
|
|
777
|
+
it("should have a name property", () => {
|
|
778
|
+
const workspace = setup(SINGLE_WORKSPACE_STUDIO_DATA).workspaces[0];
|
|
779
|
+
expect(workspace.get("name")).toBe("default");
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
it("splitId - should split the id by the first hyphen", () => {
|
|
784
|
+
expect(StudioWorkspace.splitId("app-workspace")).toEqual([
|
|
785
|
+
"app",
|
|
786
|
+
"workspace",
|
|
787
|
+
]);
|
|
788
|
+
expect(StudioWorkspace.splitId("app-workspace-test")).toEqual([
|
|
789
|
+
"app",
|
|
790
|
+
"workspace-test",
|
|
791
|
+
]);
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
it("makeId - should concatonate the strings with a hyphen", () => {
|
|
795
|
+
const appId = brandUserApplicationId("app");
|
|
796
|
+
expect(StudioWorkspace.makeId(appId, "workspace")).toBe("app-workspace");
|
|
797
|
+
expect(StudioWorkspace.makeId(appId, "workspace-test")).toBe(
|
|
798
|
+
"app-workspace-test",
|
|
799
|
+
);
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it("should implement the toProtocolResource method", () => {
|
|
803
|
+
const workspace = setup().workspaces[1];
|
|
804
|
+
expect(workspace.toProtocolResource()).toMatchInlineSnapshot(`
|
|
805
|
+
{
|
|
806
|
+
"activeDeployment": null,
|
|
807
|
+
"autoUpdatingVersion": null,
|
|
808
|
+
"basePath": "/operations-gateway",
|
|
809
|
+
"config": {},
|
|
810
|
+
"dashboardStatus": "default",
|
|
811
|
+
"dataset": "production",
|
|
812
|
+
"hasManifest": true,
|
|
813
|
+
"hasSchema": true,
|
|
814
|
+
"href": "/studio/75affa24c862a372764ceb40/operations-gateway",
|
|
815
|
+
"icon": "<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="49" fill="#FFCC32"></rect><path d="M30.5 36.6667V33C30.5 31.5413 29.9205 30.1424 28.8891 29.1109C27.8576 28.0795 26.4587 27.5 25 27.5C23.5413 27.5 22.1424 28.0795 21.1109 29.1109C20.0795 30.1424 19.5 31.5413 19.5 33V36.6667C19.5 37.1529 19.3068 37.6192 18.963 37.963C18.6192 38.3068 18.1529 38.5 17.6667 38.5H10.3333C9.8471 38.5 9.38079 38.3068 9.03697 37.963C8.69315 37.6192 8.5 37.1529 8.5 36.6667V11H15.8333V16.5H21.3333V11H28.6667V16.5H34.1667V11H41.5V36.6667C41.5 37.1529 41.3068 37.6192 40.963 37.963C40.6192 38.3068 40.1529 38.5 39.6667 38.5H32.3333C31.8471 38.5 31.3808 38.3068 31.037 37.963C30.6932 37.6192 30.5 37.1529 30.5 36.6667Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.5 22H41.5Z" fill="white"></path><path d="M8.5 22H41.5" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
816
|
+
"id": "75affa24c862a372764ceb40-operations-gateway",
|
|
817
|
+
"manifest": {
|
|
818
|
+
"createdAt": "2025-11-19T07:59:25.943Z",
|
|
819
|
+
"version": 2,
|
|
820
|
+
"workspaces": [
|
|
821
|
+
{
|
|
822
|
+
"basePath": "/360",
|
|
823
|
+
"dataset": "production",
|
|
824
|
+
"icon": "<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="50" fill="#FF5500"></rect><path d="M8.5 25C8.5 27.1668 8.92678 29.3124 9.75599 31.3143C10.5852 33.3161 11.8006 35.1351 13.3327 36.6673C14.8649 38.1994 16.6839 39.4148 18.6857 40.244C20.6876 41.0732 22.8332 41.5 25 41.5C27.1668 41.5 29.3124 41.0732 31.3143 40.244C33.3161 39.4148 35.1351 38.1994 36.6673 36.6673C38.1994 35.1351 39.4148 33.3161 40.244 31.3143C41.0732 29.3124 41.5 27.1668 41.5 25C41.5 22.8332 41.0732 20.6876 40.244 18.6857C39.4148 16.6839 38.1994 14.8649 36.6673 13.3327C35.1351 11.8006 33.3161 10.5852 31.3143 9.75599C29.3124 8.92679 27.1668 8.5 25 8.5C22.8332 8.5 20.6876 8.92679 18.6857 9.75599C16.6839 10.5852 14.8649 11.8006 13.3327 13.3327C11.8006 14.8649 10.5852 16.6839 9.75599 18.6857C8.92678 20.6876 8.5 22.8332 8.5 25Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17.666 25C17.666 29.3761 18.4386 33.5729 19.8139 36.6673C21.1892 39.7616 23.0544 41.5 24.9993 41.5C26.9443 41.5 28.8095 39.7616 30.1848 36.6673C31.5601 33.5729 32.3327 29.3761 32.3327 25C32.3327 20.6239 31.5601 16.4271 30.1848 13.3327C28.8095 10.2384 26.9443 8.5 24.9993 8.5C23.0544 8.5 21.1892 10.2384 19.8139 13.3327C18.4386 16.4271 17.666 20.6239 17.666 25Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.5 25.0003C8.5 29.052 15.8883 32.3337 25 32.3337C34.1117 32.3337 41.5 29.052 41.5 25.0003C41.5 20.9487 34.1117 17.667 25 17.667C15.8883 17.667 8.5 20.9487 8.5 25.0003Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17.666 25C17.666 29.3761 18.4386 33.5729 19.8139 36.6673C21.1892 39.7616 23.0544 41.5 24.9993 41.5C26.9443 41.5 28.8095 39.7616 30.1848 36.6673C31.5601 33.5729 32.3327 29.3761 32.3327 25C32.3327 20.6239 31.5601 16.4271 30.1848 13.3327C28.8095 10.2384 26.9443 8.5 24.9993 8.5C23.0544 8.5 21.1892 10.2384 19.8139 13.3327C18.4386 16.4271 17.666 20.6239 17.666 25Z" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
825
|
+
"name": "explorer",
|
|
826
|
+
"projectId": "hzao7xsp",
|
|
827
|
+
"schema": "cd26d36b.create-schema.json",
|
|
828
|
+
"title": "Customer 360",
|
|
829
|
+
"tools": "d7989384.create-tools.json",
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
"basePath": "/operations-gateway",
|
|
833
|
+
"dataset": "production",
|
|
834
|
+
"icon": "<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="49" fill="#FFCC32"></rect><path d="M30.5 36.6667V33C30.5 31.5413 29.9205 30.1424 28.8891 29.1109C27.8576 28.0795 26.4587 27.5 25 27.5C23.5413 27.5 22.1424 28.0795 21.1109 29.1109C20.0795 30.1424 19.5 31.5413 19.5 33V36.6667C19.5 37.1529 19.3068 37.6192 18.963 37.963C18.6192 38.3068 18.1529 38.5 17.6667 38.5H10.3333C9.8471 38.5 9.38079 38.3068 9.03697 37.963C8.69315 37.6192 8.5 37.1529 8.5 36.6667V11H15.8333V16.5H21.3333V11H28.6667V16.5H34.1667V11H41.5V36.6667C41.5 37.1529 41.3068 37.6192 40.963 37.963C40.6192 38.3068 40.1529 38.5 39.6667 38.5H32.3333C31.8471 38.5 31.3808 38.3068 31.037 37.963C30.6932 37.6192 30.5 37.1529 30.5 36.6667Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.5 22H41.5Z" fill="white"></path><path d="M8.5 22H41.5" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
835
|
+
"name": "operations-gateway",
|
|
836
|
+
"projectId": "hzao7xsp",
|
|
837
|
+
"schema": "cd26d36b.create-schema.json",
|
|
838
|
+
"title": "Operations Gateway",
|
|
839
|
+
"tools": "f63673b7.create-tools.json",
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
"basePath": "/finder",
|
|
843
|
+
"dataset": "production",
|
|
844
|
+
"icon": "<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="50" fill="#D6EDFF"></rect><rect x="12.2959" y="11.7402" width="25.41" height="13.86" fill="white"></rect><path d="M23.0732 11.356H26.9232Z" fill="white"></path><path d="M23.0732 11.356H26.9232" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M38.4734 24.8306C37.1895 35.0966 33.9824 40.2306 28.8484 40.2306H21.1484C16.0145 40.2306 12.8074 35.0966 11.5234 24.8306" fill="white"></path><path d="M38.4734 24.8306C37.1895 35.0966 33.9824 40.2306 28.8484 40.2306H21.1484C16.0145 40.2306 12.8074 35.0966 11.5234 24.8306" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M23.0732 32.5303C23.0732 33.8142 23.7143 34.4553 24.9982 34.4553C26.2822 34.4553 26.9232 33.8142 26.9232 32.5303H23.0732Z" fill="white" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M24.999 36.3804V40.2304Z" fill="white"></path><path d="M24.999 36.3804V40.2304" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M21.1494 22.9058V22.9241Z" fill="white"></path><path d="M21.1494 22.9058V22.9241" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M28.8486 22.9058V22.9241Z" fill="white"></path><path d="M28.8486 22.9058V22.9241" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11.5239 9.43018L23.0739 11.2974L11.0657 24.1718C10.7284 24.551 10.2575 24.7849 9.7516 24.8248C9.24568 24.8646 8.74398 24.7072 8.35148 24.3855C8.08529 24.1689 7.88519 23.882 7.77392 23.5574C7.66265 23.2327 7.64466 22.8834 7.72201 22.549L11.5239 9.43018Z" fill="white" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path><path d="M38.4748 9.43018L26.9248 11.2974L38.933 24.1718C39.6221 24.9572 40.8368 25.0535 41.6472 24.3855C41.9134 24.1689 42.1135 23.882 42.2248 23.5574C42.336 23.2327 42.354 22.8834 42.2767 22.549L38.4748 9.43018Z" fill="white" stroke="black" stroke-width="3.85" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
845
|
+
"name": "finder",
|
|
846
|
+
"projectId": "hzao7xsp",
|
|
847
|
+
"schema": "cd26d36b.create-schema.json",
|
|
848
|
+
"title": "Finder",
|
|
849
|
+
"tools": "790d30d6.create-tools.json",
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
"basePath": "/radar",
|
|
853
|
+
"dataset": "production",
|
|
854
|
+
"icon": "<svg viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="50" fill="#CDEA19"></rect><path d="M41.4925 24.9818H26.8258C26.8258 24.6192 26.7183 24.2647 26.5169 23.9632C26.3154 23.6617 26.0291 23.4268 25.6941 23.288C25.3591 23.1492 24.9905 23.1129 24.6348 23.1837C24.2792 23.2544 23.9525 23.429 23.6962 23.6854C23.4398 23.9418 23.2651 24.2685 23.1944 24.6241C23.1237 24.9797 23.16 25.3484 23.2987 25.6834C23.4375 26.0184 23.6725 26.3047 23.974 26.5061C24.2755 26.7076 24.6299 26.8151 24.9925 26.8151V41.4818C29.3686 41.4818 33.5654 39.7434 36.6598 36.649C39.7541 33.5547 41.4925 29.3578 41.4925 24.9818Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M32.3252 19.4821C31.5372 18.4314 30.5326 17.5624 29.3795 16.9337C28.2264 16.3051 26.9517 15.9316 25.6417 15.8385C24.3317 15.7454 23.0169 15.9349 21.7865 16.3941C20.5561 16.8534 19.4387 17.5716 18.5101 18.5003C17.5814 19.4289 16.8631 20.5463 16.4039 21.7767C15.9446 23.0072 15.7552 24.3219 15.8483 25.6319C15.9414 26.9419 16.3149 28.2167 16.9435 29.3698C17.5721 30.5229 18.4412 31.5274 19.4919 32.3154" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M40.55 19.4821C39.6182 16.8561 38.0365 14.5088 35.9524 12.6592C33.8683 10.8096 31.3498 9.51795 28.6317 8.90464C25.9136 8.29133 23.0845 8.37637 20.4081 9.15184C17.7317 9.9273 15.2953 11.3679 13.3261 13.3393C11.3569 15.3108 9.91908 17.7488 9.14665 20.426C8.37422 23.1033 8.29238 25.9325 8.90876 28.6499C9.52514 31.3673 10.8197 33.8844 12.6716 35.9664C14.5236 38.0483 16.8726 39.6274 19.4997 40.5562" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
855
|
+
"name": "radar",
|
|
856
|
+
"projectId": "hzao7xsp",
|
|
857
|
+
"schema": "cd26d36b.create-schema.json",
|
|
858
|
+
"title": "Radar",
|
|
859
|
+
"tools": "6e3a5662.create-tools.json",
|
|
860
|
+
},
|
|
861
|
+
{
|
|
862
|
+
"basePath": "/atlas",
|
|
863
|
+
"dataset": "production",
|
|
864
|
+
"icon": "<svg width="50" height="49" viewBox="0 0 50 49" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="50" height="49" fill="#40E8AF"></rect><path d="M17.667 31.8332L21.3337 20.8332L32.3337 17.1665L28.667 28.1665L17.667 31.8332Z" fill="white" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.5 24.5C8.5 26.6668 8.92678 28.8124 9.75599 30.8143C10.5852 32.8161 11.8006 34.6351 13.3327 36.1673C14.8649 37.6994 16.6839 38.9148 18.6857 39.744C20.6876 40.5732 22.8332 41 25 41C27.1668 41 29.3124 40.5732 31.3143 39.744C33.3161 38.9148 35.1351 37.6994 36.6673 36.1673C38.1994 34.6351 39.4148 32.8161 40.244 30.8143C41.0732 28.8124 41.5 26.6668 41.5 24.5C41.5 22.3332 41.0732 20.1876 40.244 18.1857C39.4148 16.1839 38.1994 14.3649 36.6673 12.8327C35.1351 11.3006 33.3161 10.0852 31.3143 9.25599C29.3124 8.42679 27.1668 8 25 8C22.8332 8 20.6876 8.42679 18.6857 9.25599C16.6839 10.0852 14.8649 11.3006 13.3327 12.8327C11.8006 14.3649 10.5852 16.1839 9.75599 18.1857C8.92678 20.1876 8.5 22.3332 8.5 24.5Z" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M25 8V11.6667" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M25 37.3335V41.0002" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.5 24.5H12.1667" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path><path d="M37.833 24.5H41.4997" stroke="black" stroke-width="3.66667" stroke-linecap="round" stroke-linejoin="round"></path></svg>",
|
|
865
|
+
"name": "atlas",
|
|
866
|
+
"projectId": "hzao7xsp",
|
|
867
|
+
"schema": "b0fefb08.create-schema.json",
|
|
868
|
+
"title": "Atlas",
|
|
869
|
+
"tools": "9597875e.create-tools.json",
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
"basePath": "/resources",
|
|
873
|
+
"dataset": "production",
|
|
874
|
+
"icon": "<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3 19a9 9 0 0 1 9 0a9 9 0 0 1 9 0"></path><path d="M3 6a9 9 0 0 1 9 0a9 9 0 0 1 9 0"></path><path d="M3 6l0 13"></path><path d="M12 6l0 13"></path><path d="M21 6l0 13"></path></svg>",
|
|
875
|
+
"name": "resources",
|
|
876
|
+
"projectId": "hzao7xsp",
|
|
877
|
+
"schema": "b0fefb08.create-schema.json",
|
|
878
|
+
"title": "Resource Center",
|
|
879
|
+
"tools": "c704250f.create-tools.json",
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
"basePath": "/data",
|
|
883
|
+
"dataset": "production",
|
|
884
|
+
"icon": "<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-12a2 2 0 0 0 -2 -2h-2"></path><path d="M9 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z"></path><path d="M9 17v-4"></path><path d="M12 17v-1"></path><path d="M15 17v-2"></path><path d="M12 17v-1"></path></svg>",
|
|
885
|
+
"name": "data",
|
|
886
|
+
"projectId": "hzao7xsp",
|
|
887
|
+
"schema": "b0fefb08.create-schema.json",
|
|
888
|
+
"title": "Data Hub",
|
|
889
|
+
"tools": "08382af6.create-tools.json",
|
|
890
|
+
},
|
|
891
|
+
{
|
|
892
|
+
"basePath": "/operations",
|
|
893
|
+
"dataset": "production",
|
|
894
|
+
"icon": "<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M12 8a2 2 0 0 1 2 2v4a2 2 0 1 1 -4 0v-4a2 2 0 0 1 2 -2"></path><path d="M17 15c.345 .6 1.258 1 2 1a2 2 0 1 0 0 -4a2 2 0 1 1 0 -4c.746 0 1.656 .394 2 1"></path><path d="M3 15c.345 .6 1.258 1 2 1a2 2 0 1 0 0 -4a2 2 0 1 1 0 -4c.746 0 1.656 .394 2 1"></path></svg>",
|
|
895
|
+
"name": "operations",
|
|
896
|
+
"projectId": "hzao7xsp",
|
|
897
|
+
"schema": "cd26d36b.create-schema.json",
|
|
898
|
+
"title": "SupportOS™",
|
|
899
|
+
"tools": "a6046e2d.create-tools.json",
|
|
900
|
+
},
|
|
901
|
+
],
|
|
902
|
+
},
|
|
903
|
+
"name": "operations-gateway",
|
|
904
|
+
"projectId": "hzao7xsp",
|
|
905
|
+
"schema": "cd26d36b.create-schema.json",
|
|
906
|
+
"title": "Operations Gateway",
|
|
907
|
+
"tools": "f63673b7.create-tools.json",
|
|
908
|
+
"type": "studio",
|
|
909
|
+
"updatedAt": "2025-05-06T20:12:05.955Z",
|
|
910
|
+
"url": "https://360.sanity.build/",
|
|
911
|
+
"urlType": "external",
|
|
912
|
+
"userApplicationId": "75affa24c862a372764ceb40",
|
|
913
|
+
"version": undefined,
|
|
914
|
+
}
|
|
915
|
+
`);
|
|
916
|
+
|
|
917
|
+
expectTypeOf(
|
|
918
|
+
workspace.toProtocolResource(),
|
|
919
|
+
).toEqualTypeOf<ProtocolStudioResource>();
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
it("should be able to access the studio application", () => {
|
|
923
|
+
const studioApplication = setup();
|
|
924
|
+
const workspace = studioApplication.workspaces[0];
|
|
925
|
+
|
|
926
|
+
expect(workspace.studio).toBe(studioApplication);
|
|
927
|
+
});
|
|
928
|
+
});
|