@sanity/runtime-cli 13.0.3 → 13.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +18 -18
  2. package/dist/actions/blueprints/blueprint.d.ts +6 -3
  3. package/dist/actions/blueprints/blueprint.js +18 -8
  4. package/dist/actions/functions/dev.d.ts +1 -1
  5. package/dist/actions/functions/dev.js +2 -2
  6. package/dist/actions/git.d.ts +4 -1
  7. package/dist/actions/git.js +3 -3
  8. package/dist/baseCommands.d.ts +4 -0
  9. package/dist/baseCommands.js +8 -0
  10. package/dist/commands/blueprints/add.js +1 -0
  11. package/dist/commands/blueprints/config.js +1 -0
  12. package/dist/commands/blueprints/deploy.js +1 -0
  13. package/dist/commands/blueprints/destroy.js +1 -0
  14. package/dist/commands/blueprints/doctor.js +1 -0
  15. package/dist/commands/blueprints/info.js +1 -0
  16. package/dist/commands/blueprints/init.js +1 -0
  17. package/dist/commands/blueprints/logs.js +1 -0
  18. package/dist/commands/blueprints/plan.js +1 -0
  19. package/dist/commands/blueprints/stacks.js +1 -0
  20. package/dist/commands/functions/add.js +1 -0
  21. package/dist/commands/functions/dev.js +1 -0
  22. package/dist/commands/functions/env/add.js +1 -0
  23. package/dist/commands/functions/env/list.js +1 -0
  24. package/dist/commands/functions/env/remove.js +1 -0
  25. package/dist/commands/functions/logs.js +1 -0
  26. package/dist/commands/functions/test.js +1 -0
  27. package/dist/constants.d.ts +1 -0
  28. package/dist/constants.js +1 -0
  29. package/dist/cores/blueprints/doctor.js +3 -2
  30. package/dist/cores/blueprints/init.d.ts +2 -0
  31. package/dist/cores/blueprints/init.js +40 -9
  32. package/dist/cores/functions/add.js +12 -1
  33. package/dist/cores/functions/dev.js +1 -1
  34. package/dist/cores/functions/logs.js +6 -1
  35. package/dist/cores/index.d.ts +4 -2
  36. package/dist/cores/index.js +4 -2
  37. package/dist/server/app.d.ts +1 -1
  38. package/dist/server/app.js +6 -4
  39. package/dist/server/handlers/invoke.d.ts +1 -1
  40. package/dist/server/handlers/invoke.js +2 -2
  41. package/dist/server/static/api.d.ts +41 -0
  42. package/dist/server/static/api.js +29 -6
  43. package/dist/server/static/components/filters.js +62 -56
  44. package/dist/server/static/components/function-list.js +1 -1
  45. package/dist/server/static/components/payload-panel.js +33 -4
  46. package/dist/server/static/components/run-panel.js +12 -4
  47. package/dist/server/static/vendor/vendor.bundle.js +19 -10
  48. package/dist/utils/child-process-wrapper.js +3 -2
  49. package/dist/utils/display/blueprints-formatting.d.ts +2 -2
  50. package/dist/utils/display/blueprints-formatting.js +10 -3
  51. package/dist/utils/display/prompt.js +22 -15
  52. package/dist/utils/display/resources-formatting.d.ts +2 -1
  53. package/dist/utils/display/resources-formatting.js +31 -0
  54. package/dist/utils/find-function.js +6 -1
  55. package/dist/utils/functions/resource-to-arc.js +11 -2
  56. package/dist/utils/types.d.ts +10 -4
  57. package/dist/utils/types.js +4 -1
  58. package/dist/utils/validate/index.d.ts +3 -0
  59. package/dist/utils/validate/index.js +35 -0
  60. package/oclif.manifest.json +120 -1
  61. package/package.json +16 -17
@@ -8,6 +8,7 @@ import { createEmptyStack } from '../../actions/blueprints/stacks.js';
8
8
  import { writeGitignoreFile } from '../../actions/git.js';
9
9
  import { writeOrUpdateNodeDependency } from '../../actions/node.js';
10
10
  import { verifyExampleExists, writeExample } from '../../actions/sanity/examples.js';
11
+ import { getProject } from '../../actions/sanity/projects.js';
11
12
  import { BLUEPRINT_CONFIG_DIR, BLUEPRINT_CONFIG_FILE } from '../../config.js';
12
13
  import { check, filePathRelativeToCwd, labeledId, warn } from '../../utils/display/presenters.js';
13
14
  import { promptForBlueprintType, promptForProject, promptForStack, } from '../../utils/display/prompt.js';
@@ -15,7 +16,7 @@ import { blueprintConfigCore } from './config.js';
15
16
  const SCOPE_PROJECT = 'project';
16
17
  const SCOPE_ORGANIZATION = 'organization';
17
18
  export async function blueprintInitCore(options) {
18
- const { bin = 'sanity', log, token, args, flags } = options;
19
+ const { bin = 'sanity', log, token, knownProjectId, args, flags, validateResources } = options;
19
20
  const { dir: flagDir, example: flagExample, 'blueprint-type': flagBlueprintType, 'project-id': flagProjectId, 'organization-id': flagOrganizationId, 'stack-id': flagStackId, 'stack-name': flagStackName, verbose: v = false, } = flags;
20
21
  const { dir: argDir } = args;
21
22
  const userProvidedDirName = argDir || flagDir;
@@ -54,12 +55,13 @@ export async function blueprintInitCore(options) {
54
55
  if (!overwrite)
55
56
  return { success: false, error: 'Initialization cancelled.' };
56
57
  }
57
- const existingBlueprint = await readLocalBlueprint(log, existingBlueprintFile.blueprintFilePath);
58
+ const existingBlueprint = await readLocalBlueprint(log, { resources: validateResources || false }, existingBlueprintFile.blueprintFilePath);
58
59
  return blueprintConfigCore({
59
60
  blueprint: existingBlueprint,
60
61
  bin,
61
62
  log,
62
63
  token,
64
+ validateResources,
63
65
  flags: {
64
66
  edit: true,
65
67
  'project-id': flagProjectId,
@@ -84,6 +86,7 @@ export async function blueprintInitCore(options) {
84
86
  organizationId: flagOrganizationId,
85
87
  stackId: flagStackId,
86
88
  stackName: flagStackName,
89
+ knownProjectId,
87
90
  log,
88
91
  token,
89
92
  });
@@ -169,7 +172,7 @@ async function handleExampleInitialization(options) {
169
172
  return { success: true };
170
173
  }
171
174
  export async function resolveScopeAndStack(params) {
172
- const { projectId, organizationId, stackId, stackName, log, token } = params;
175
+ const { projectId, organizationId, stackId, stackName, knownProjectId, log, token } = params;
173
176
  let scopeType = SCOPE_PROJECT;
174
177
  let scopeId;
175
178
  if (projectId) {
@@ -195,10 +198,33 @@ export async function resolveScopeAndStack(params) {
195
198
  resolvedStackId = stack.id;
196
199
  }
197
200
  if (!scopeId) {
198
- log('\nBlueprints are associated with a Sanity Project. Please select one:');
199
- const pickedProject = await promptForProject({ token, logger: log });
200
- scopeType = SCOPE_PROJECT;
201
- scopeId = pickedProject.projectId;
201
+ log('\nBlueprints are associated with a Sanity project.');
202
+ // If we have a CLI project ID, offer it as a suggestion
203
+ if (knownProjectId) {
204
+ const { ok, project } = await getProject({
205
+ token,
206
+ scopeId: knownProjectId,
207
+ scopeType: 'project',
208
+ logger: log,
209
+ });
210
+ if (ok && project) {
211
+ const useCliProject = await confirm({
212
+ message: `The CLI is configured to use "${project.displayName}" (${knownProjectId}). Use this for the blueprint?`,
213
+ default: true,
214
+ });
215
+ if (useCliProject) {
216
+ scopeType = SCOPE_PROJECT;
217
+ scopeId = knownProjectId;
218
+ }
219
+ }
220
+ }
221
+ // If still no scope (no knownProjectId, lookup failed, or user declined), prompt for selection
222
+ if (!scopeId) {
223
+ log('Select a project:');
224
+ const pickedProject = await promptForProject({ token, logger: log });
225
+ scopeType = SCOPE_PROJECT;
226
+ scopeId = pickedProject.projectId;
227
+ }
202
228
  }
203
229
  if (!resolvedStackId) {
204
230
  log('\nBlueprints are deployed to a "Stack".');
@@ -254,8 +280,13 @@ export async function createBlueprintFiles(params) {
254
280
  ...(scopeType === SCOPE_ORGANIZATION ? { organizationId: scopeId } : { projectId: scopeId }),
255
281
  });
256
282
  log(check(`${chalk.bold('Added configuration:')} ${displayPath}/${BLUEPRINT_CONFIG_DIR}/${BLUEPRINT_CONFIG_FILE}`));
257
- writeGitignoreFile(blueprintFilePath);
258
- log(check(`${chalk.bold('Added .gitignore:')} ${displayPath}/.gitignore`));
283
+ const gitignoreResult = writeGitignoreFile(blueprintFilePath);
284
+ if (gitignoreResult.action === 'created') {
285
+ log(check(`${chalk.bold('Added .gitignore:')} ${displayPath}/.gitignore`));
286
+ }
287
+ else if (gitignoreResult.action === 'updated') {
288
+ log(check(`${chalk.bold('Updated .gitignore:')} ${displayPath}/.gitignore`));
289
+ }
259
290
  if (blueprintExtension !== 'json') {
260
291
  const blueprintsPackage = '@sanity/blueprints';
261
292
  try {
@@ -6,6 +6,7 @@ import { highlight } from 'cardinal';
6
6
  import chalk from 'chalk';
7
7
  import { createFunctionResource } from '../../actions/blueprints/resources.js';
8
8
  import { verifyExampleExists, writeExample } from '../../actions/sanity/examples.js';
9
+ import { SANITY_FUNCTION_MEDIA_LIBRARY_ASSET, SANITY_FUNCTION_SCHEDULE } from '../../constants.js';
9
10
  import { check, indent, warn } from '../../utils/display/presenters.js';
10
11
  import { validateFunctionName } from '../../utils/validate/resource.js';
11
12
  const generateFunctionBlueprintResourceTemplate = (fnName, eventNames) => {
@@ -71,7 +72,17 @@ export async function functionAddCore(options) {
71
72
  }
72
73
  else {
73
74
  const objectLiteral = configString.replace(/^(\s*)"([a-zA-Z_$][a-zA-Z0-9_$]*)":/gm, '$1$2:');
74
- log(indent(highlight(`defineDocumentFunction(${objectLiteral})`)));
75
+ let type = 'Document';
76
+ switch (functionConfig.type) {
77
+ case SANITY_FUNCTION_MEDIA_LIBRARY_ASSET:
78
+ type = 'MediaLibraryAsset';
79
+ break;
80
+ case SANITY_FUNCTION_SCHEDULE:
81
+ type = 'Schedule';
82
+ break;
83
+ default:
84
+ }
85
+ log(indent(highlight(`define${type}Function(${objectLiteral})`)));
75
86
  }
76
87
  }
77
88
  else {
@@ -7,7 +7,7 @@ export async function functionDevCore(options) {
7
7
  ? { timeout }
8
8
  : undefined;
9
9
  try {
10
- await dev(host, Number(port), log, executionOptions);
10
+ await dev(host, Number(port), log, options.validateResources || false, executionOptions);
11
11
  log(`Server is running on http://${host}:${port}\n`);
12
12
  return {
13
13
  success: true,
@@ -105,7 +105,12 @@ function formatLog(time, level, message, utc) {
105
105
  const [dateString, timeString] = utc
106
106
  ? date.toISOString().slice(0, 19).split('T')
107
107
  : [date.toLocaleDateString(), date.toLocaleTimeString()];
108
- return [chalk.bold(dateString), chalk.bold.blue(timeString), logLevel(level), message].join(' ');
108
+ return [
109
+ chalk.bold(dateString),
110
+ chalk.bold.blue(timeString),
111
+ logLevel(level.toUpperCase()),
112
+ message,
113
+ ].join(' ');
109
114
  }
110
115
  function logLevel(level) {
111
116
  if (level === 'ERROR')
@@ -8,6 +8,8 @@ export interface CoreConfig {
8
8
  bin: string;
9
9
  /** The log output function. */
10
10
  log: ReturnType<typeof Logger>;
11
+ /** Enable resource validation during parsing */
12
+ validateResources?: boolean;
11
13
  }
12
14
  export interface BlueprintConfig extends CoreConfig {
13
15
  token: string;
@@ -43,7 +45,7 @@ type InitBlueprintConfigParams = CoreConfig & ({
43
45
  validateToken?: false;
44
46
  token?: string;
45
47
  });
46
- export declare function initBlueprintConfig({ bin, log, token, validateToken, }: InitBlueprintConfigParams): Promise<Result<BlueprintConfig>>;
47
- export declare function initDeployedBlueprintConfig(config: Partial<BlueprintConfig> & Pick<BlueprintConfig, 'bin' | 'log' | 'token'> & {
48
+ export declare function initBlueprintConfig({ bin, log, token, validateResources, validateToken, }: InitBlueprintConfigParams): Promise<Result<BlueprintConfig>>;
49
+ export declare function initDeployedBlueprintConfig(config: Partial<BlueprintConfig> & Pick<BlueprintConfig, 'bin' | 'log' | 'token' | 'validateResources'> & {
48
50
  validateToken?: boolean;
49
51
  }): Promise<Result<DeployedBlueprintConfig>>;
@@ -5,7 +5,7 @@ import { niceId } from '../utils/display/presenters.js';
5
5
  import { validTokenOrErrorMessage } from '../utils/validated-token.js';
6
6
  export * as blueprintsCores from './blueprints/index.js';
7
7
  export * as functionsCores from './functions/index.js';
8
- export async function initBlueprintConfig({ bin, log, token, validateToken = true, }) {
8
+ export async function initBlueprintConfig({ bin, log, token, validateResources = false, validateToken = true, }) {
9
9
  let checkedToken = token;
10
10
  if (!token || (token && validateToken)) {
11
11
  const tokenCheck = await validTokenOrErrorMessage(log, token);
@@ -17,7 +17,7 @@ export async function initBlueprintConfig({ bin, log, token, validateToken = tru
17
17
  if (!checkedToken) {
18
18
  return { ok: false, error: 'A valid token is required but was not provided.' };
19
19
  }
20
- const blueprint = await readLocalBlueprint(log);
20
+ const blueprint = await readLocalBlueprint(log, { resources: validateResources });
21
21
  if (blueprint.errors.length > 0) {
22
22
  log(presentBlueprintParserErrors(blueprint.errors));
23
23
  return { ok: false, error: 'Blueprint file contains errors.' };
@@ -29,6 +29,7 @@ export async function initBlueprintConfig({ bin, log, token, validateToken = tru
29
29
  blueprint,
30
30
  log,
31
31
  token: checkedToken,
32
+ validateResources,
32
33
  },
33
34
  };
34
35
  }
@@ -67,6 +68,7 @@ export async function initDeployedBlueprintConfig(config) {
67
68
  stackId,
68
69
  auth,
69
70
  deployedStack: stackResponse.stack,
71
+ validateResources: config.validateResources,
70
72
  },
71
73
  };
72
74
  }
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from '../utils/logger.js';
2
2
  import { type InvokeExecutionOptions } from '../utils/types.js';
3
- declare const app: (host: string, port: number, logger: ReturnType<typeof Logger>, executionOptions?: Partial<InvokeExecutionOptions>) => void;
3
+ declare const app: (host: string, port: number, logger: ReturnType<typeof Logger>, validateResources: boolean, executionOptions?: Partial<InvokeExecutionOptions>) => void;
4
4
  declare function parseDocumentUrl(url: string): {
5
5
  projectId: string;
6
6
  dataset: string;
@@ -7,13 +7,15 @@ import config from '../config.js';
7
7
  import { isRecord } from '../utils/is-record.js';
8
8
  import { isEventType, isGroqContextOptions, } from '../utils/types.js';
9
9
  import { handleInvokeRequest } from './handlers/invoke.js';
10
- const app = (host, port, logger, executionOptions) => {
10
+ const app = (host, port, logger, validateResources, executionOptions) => {
11
11
  const requestListener = async (req, res) => {
12
12
  res.setHeader('Content-Type', 'application/json');
13
13
  switch (true) {
14
14
  case req.url === '/blueprint': {
15
15
  try {
16
- const { parsedBlueprint, projectId, organizationId } = await readLocalBlueprint(logger);
16
+ const { parsedBlueprint, projectId, organizationId } = await readLocalBlueprint(logger, {
17
+ resources: validateResources,
18
+ });
17
19
  res.setHeader('Content-Type', 'application/json');
18
20
  res.writeHead(200);
19
21
  res.end(JSON.stringify({ parsedBlueprint, projectId, organizationId })); // Use blueprint directly
@@ -42,7 +44,7 @@ const app = (host, port, logger, executionOptions) => {
42
44
  delete context.clientOptions.token;
43
45
  }
44
46
  }
45
- const result = await handleInvokeRequest(functionName, event, metadata, context, logger, executionOptions);
47
+ const result = await handleInvokeRequest(functionName, event, metadata, context, logger, validateResources, executionOptions);
46
48
  // Add Server-Timing header
47
49
  const timingHeaders = [];
48
50
  for (const [key, value] of Object.entries(result.timings)) {
@@ -230,7 +232,7 @@ const app = (host, port, logger, executionOptions) => {
230
232
  const wss = new WebSocketServer({ port: 8974 });
231
233
  wss.on('connection', async function connection(ws) {
232
234
  ws.on('error', console.error);
233
- const { fileInfo } = await readLocalBlueprint(logger);
235
+ const { fileInfo } = await readLocalBlueprint(logger, { resources: validateResources });
234
236
  watchFile(fileInfo.blueprintFilePath, { interval: 2007 }, async () => {
235
237
  ws.send('reload-blueprint');
236
238
  });
@@ -1,5 +1,5 @@
1
1
  import type { Logger } from '../../utils/logger.js';
2
2
  import type { InvocationResponse, InvokeContextOptions, InvokeExecutionOptions, InvokePayloadMetadata } from '../../utils/types.js';
3
- export declare function handleInvokeRequest(functionName: string, event: Record<string, unknown>, metadata: InvokePayloadMetadata, context: InvokeContextOptions, logger: ReturnType<typeof Logger>, executionOptions?: Partial<InvokeExecutionOptions>): Promise<InvocationResponse & {
3
+ export declare function handleInvokeRequest(functionName: string, event: Record<string, unknown>, metadata: InvokePayloadMetadata, context: InvokeContextOptions, logger: ReturnType<typeof Logger>, validateResources: boolean, executionOptions?: Partial<InvokeExecutionOptions>): Promise<InvocationResponse & {
4
4
  timings: Record<string, number>;
5
5
  }>;
@@ -1,9 +1,9 @@
1
1
  import { readLocalBlueprint } from '../../actions/blueprints/blueprint.js';
2
2
  import { findFunctionInBlueprint } from '../../utils/find-function.js';
3
3
  import invoke from '../../utils/invoke-local.js';
4
- export async function handleInvokeRequest(functionName, event, metadata, context, logger, executionOptions) {
4
+ export async function handleInvokeRequest(functionName, event, metadata, context, logger, validateResources, executionOptions) {
5
5
  const start = performance.now();
6
- const { parsedBlueprint } = await readLocalBlueprint(logger);
6
+ const { parsedBlueprint } = await readLocalBlueprint(logger, { resources: validateResources });
7
7
  const resource = findFunctionInBlueprint(parsedBlueprint, functionName);
8
8
  const readBlueprintTime = performance.now() - start;
9
9
  const payload = {
@@ -0,0 +1,41 @@
1
+ export type SubscribeFunc = (fn: () => void) => void
2
+
3
+ export interface ServerAPI {
4
+ blueprint(): Promise<void>
5
+ document({
6
+ projectId,
7
+ dataset,
8
+ docId,
9
+ }: {
10
+ projectId: string
11
+ dataset: string
12
+ docId: string
13
+ }): Promise<void>
14
+ invoke({
15
+ context,
16
+ event,
17
+ metadata,
18
+ }: {
19
+ context: unknown
20
+ event: unknown
21
+ metadata: unknown
22
+ }): Promise<void>
23
+ projects(): Promise<void>
24
+ datasets(selectedProject: string): Promise<void>
25
+ organizations(): Promise<void>
26
+ mediaLibraries(selectedOrganization: string): Promise<void>
27
+ asset({
28
+ organizationId,
29
+ mediaLibraryId,
30
+ docId,
31
+ }: {
32
+ organizationId: string
33
+ mediaLibraryId: string
34
+ docId: string
35
+ }): Promise<void>
36
+ store: Record<string, unknown> & {subscribe: SubscribeFunc; unsubscribe: SubscribeFunc}
37
+ subscribe: SubscribeFunc
38
+ unsubscribe: SubscribeFunc
39
+ }
40
+
41
+ export default function API(): ServerAPI
@@ -4,6 +4,7 @@ import {Store} from './vendor/vendor.bundle.js'
4
4
  // list of events to simulate
5
5
  const events = ['create', 'update', 'delete'].map((e) => ({name: e}))
6
6
 
7
+ /** @type {Record<string, unknown>} */
7
8
  // eslint-disable-next-line new-cap
8
9
  const store = Store({events, selectedEvent: events[0].name})
9
10
 
@@ -23,6 +24,12 @@ export default function API() {
23
24
  }
24
25
  }
25
26
 
27
+ /**
28
+ * @param {object} params
29
+ * @param {unknown} params.context
30
+ * @param {unknown} params.event
31
+ * @param {unknown} params.metadata
32
+ */
26
33
  function invoke({context, event, metadata}) {
27
34
  store.inprogress = true
28
35
  const start = Date.now()
@@ -31,7 +38,7 @@ function invoke({context, event, metadata}) {
31
38
  func: store.selectedIndex,
32
39
  metadata,
33
40
  }
34
- fetch('/invoke', {
41
+ return fetch('/invoke', {
35
42
  body: JSON.stringify(payload),
36
43
  headers: {
37
44
  'Content-Type': 'application/json',
@@ -52,7 +59,7 @@ function invoke({context, event, metadata}) {
52
59
  }
53
60
 
54
61
  function blueprint() {
55
- fetch('/blueprint')
62
+ return fetch('/blueprint')
56
63
  .then((response) => response.json())
57
64
  .then((blueprint) => {
58
65
  const {parsedBlueprint, projectId, organizationId} = blueprint
@@ -72,7 +79,7 @@ function blueprint() {
72
79
  }
73
80
 
74
81
  function projects() {
75
- fetch('/projects')
82
+ return fetch('/projects')
76
83
  .then((response) => response.json())
77
84
  .then(async (projects) => {
78
85
  store.projects = projects
@@ -84,8 +91,11 @@ function projects() {
84
91
  })
85
92
  }
86
93
 
94
+ /**
95
+ * @param {string} selectedProject
96
+ */
87
97
  function datasets(selectedProject) {
88
- fetch(`/datasets?project=${selectedProject}`)
98
+ return fetch(`/datasets?project=${selectedProject}`)
89
99
  .then((response) => response.json())
90
100
  .then((datasets) => {
91
101
  store.datasets = datasets
@@ -96,6 +106,12 @@ function datasets(selectedProject) {
96
106
  })
97
107
  }
98
108
 
109
+ /**
110
+ * @param {object} params
111
+ * @param {string} params.projectId
112
+ * @param {string} params.dataset
113
+ * @param {string} params.docId
114
+ */
99
115
  function document({projectId, dataset, docId}) {
100
116
  return fetch(`/document?project=${projectId}&dataset=${dataset}&doc=${docId}`)
101
117
  .then((response) => response.json())
@@ -108,7 +124,7 @@ function document({projectId, dataset, docId}) {
108
124
  }
109
125
 
110
126
  function organizations() {
111
- fetch('/organizations')
127
+ return fetch('/organizations')
112
128
  .then((response) => response.json())
113
129
  .then(async (organizations) => {
114
130
  store.organizations = organizations
@@ -123,7 +139,7 @@ function organizations() {
123
139
  }
124
140
 
125
141
  function mediaLibraries(selectedOrganization) {
126
- fetch(`/media-libraries?organization=${selectedOrganization}`)
142
+ return fetch(`/media-libraries?organization=${selectedOrganization}`)
127
143
  .then((response) => response.json())
128
144
  .then((mediaLibraries) => {
129
145
  store.mediaLibraries = mediaLibraries
@@ -136,6 +152,13 @@ function mediaLibraries(selectedOrganization) {
136
152
  })
137
153
  }
138
154
 
155
+ /**
156
+ *
157
+ * @param {object} params
158
+ * @param {string} params.organizationId
159
+ * @param {string} params.mediaLibraryId
160
+ * @param {string} params.docId
161
+ */
139
162
  function asset({organizationId, mediaLibraryId, docId}) {
140
163
  return fetch(`/asset?organization=${organizationId}&medialibrary=${mediaLibraryId}&doc=${docId}`)
141
164
  .then((response) => response.json())
@@ -56,18 +56,6 @@ form input {
56
56
  </style>
57
57
  <form class="gap-2 pad-l-3 pad-b-3 border-bottom">
58
58
  <fieldset class="flex gap-2">
59
- <legend class="config-label">Client Options</legend>
60
- <div id="dynamic-dropdowns" class="flex gap-2"></div>
61
- <select-dropdown
62
- label="Event"
63
- store-key="events"
64
- selected-key="selectedEvent"
65
- value-prop="name"
66
- label-prop="name"
67
- ></select-dropdown>
68
- <api-version></api-version>
69
- <with-token></with-token>
70
- <document-id></document-id>
71
59
  </fieldset>
72
60
  </form>
73
61
  `
@@ -87,54 +75,72 @@ class FiltersComponent extends ApiBaseElement {
87
75
  }
88
76
 
89
77
  renderFilters = () => {
90
- const docFunction = this.api.store.selectedFunctionType === 'sanity.function.document'
78
+ const docFunction = this.api.store.selectedFunctionType === this.SANITY_FUNCTION_DOCUMENT
91
79
  const mediaFunction = this.api.store.selectedFunctionType?.startsWith(
92
- 'sanity.function.media-library',
80
+ this.SANITY_FUNCTION_MEDIA_LIBRARY_ASSET,
93
81
  )
82
+ const scheduleFunction = this.api.store.selectedFunctionType === this.SANITY_FUNCTION_SCHEDULE
83
+
84
+ const container = this.shadowRoot.querySelector('fieldset')
85
+ container.innerHTML = this.buildFilters(docFunction, mediaFunction, scheduleFunction)
86
+ }
94
87
 
95
- const container = this.shadowRoot.querySelector('#dynamic-dropdowns')
96
-
97
- if (docFunction) {
98
- container.innerHTML = `
99
- <select-dropdown
100
- label="Project"
101
- store-key="projects"
102
- selected-key="selectedProject"
103
- value-prop="id"
104
- label-prop="displayName"
105
- trigger-fetch
106
- ></select-dropdown>
107
- <select-dropdown
108
- label="Dataset"
109
- store-key="datasets"
110
- selected-key="selectedDataset"
111
- value-prop="name"
112
- label-prop="name"
113
- subscribe-to="selectedProject"
114
- ></select-dropdown>
115
- `
116
- } else if (mediaFunction) {
117
- container.innerHTML = `
118
- <select-dropdown
119
- label="Organization"
120
- store-key="organizations"
121
- selected-key="selectedOrganization"
122
- value-prop="id"
123
- label-prop="name"
124
- trigger-fetch
125
- ></select-dropdown>
126
- <select-dropdown
127
- label="Media Library"
128
- store-key="mediaLibraries"
129
- selected-key="selectedMediaLibrary"
130
- value-prop="id"
131
- label-prop="id"
132
- subscribe-to="selectedOrganization"
133
- ></select-dropdown>
134
- `
135
- } else {
136
- container.innerHTML = ''
88
+ buildFilters = (docFunction, mediaFunction, scheduleFunction) => {
89
+ return `
90
+ <legend class="config-label">Client Options</legend>
91
+ <div id="dynamic-dropdowns" class="flex gap-2">
92
+ ${
93
+ docFunction || scheduleFunction
94
+ ? `<select-dropdown
95
+ label="Project"
96
+ store-key="projects"
97
+ selected-key="selectedProject"
98
+ value-prop="id"
99
+ label-prop="displayName"
100
+ trigger-fetch
101
+ ></select-dropdown>
102
+ <select-dropdown
103
+ label="Dataset"
104
+ store-key="datasets"
105
+ selected-key="selectedDataset"
106
+ value-prop="name"
107
+ label-prop="name"
108
+ subscribe-to="selectedProject"
109
+ ></select-dropdown>`
110
+ : `
111
+ <select-dropdown
112
+ label="Organization"
113
+ store-key="organizations"
114
+ selected-key="selectedOrganization"
115
+ value-prop="id"
116
+ label-prop="name"
117
+ trigger-fetch
118
+ ></select-dropdown>
119
+ <select-dropdown
120
+ label="Media Library"
121
+ store-key="mediaLibraries"
122
+ selected-key="selectedMediaLibrary"
123
+ value-prop="id"
124
+ label-prop="id"
125
+ subscribe-to="selectedOrganization"
126
+ ></select-dropdown>`
127
+ }
128
+ </div>
129
+ ${
130
+ docFunction || mediaFunction
131
+ ? `<select-dropdown
132
+ label="Event"
133
+ store-key="events"
134
+ selected-key="selectedEvent"
135
+ value-prop="name"
136
+ label-prop="name"
137
+ ></select-dropdown>`
138
+ : ''
137
139
  }
140
+ <api-version></api-version>
141
+ <with-token></with-token>
142
+ ${docFunction || mediaFunction ? `<document-id></document-id>` : ''}
143
+ `
138
144
  }
139
145
 
140
146
  disconnectedCallback() {
@@ -78,7 +78,7 @@ class FunctionList extends ApiBaseElement {
78
78
  })
79
79
  .join('')
80
80
  } else {
81
- this.list.innerHTML = '<option class="pad-2">No Blueprint found</li>'
81
+ this.list.innerHTML = '<option class="pad-2">No Functions found</li>'
82
82
  this.select.innerHTML = '<option>No blueprint.json file found</option>'
83
83
  }
84
84
  }
@@ -1,10 +1,12 @@
1
1
  /* globals customElements document */
2
2
 
3
- import {basicSetup, EditorView, json} from '../vendor/vendor.bundle.js'
3
+ import {basicSetup, Compartment, EditorView, json} from '../vendor/vendor.bundle.js'
4
4
  import {ApiBaseElement} from './api-base.js'
5
5
  import {sanityCodeMirrorTheme} from './codemirror-theme.js'
6
6
  import {getSharedStyleSheets} from './shared-styles.js'
7
7
 
8
+ const editableCompartment = new Compartment()
9
+
8
10
  const template = document.createElement('template')
9
11
  template.innerHTML = `
10
12
  <style>
@@ -73,8 +75,32 @@ class PayloadPanel extends ApiBaseElement {
73
75
 
74
76
  this.api.subscribe(this.updatePayload, ['document'])
75
77
  this.api.subscribe(this.updateSelectedEvent, ['selectedEvent'])
78
+ this.api.subscribe(this.updateCodeMirror, ['selectedFunctionType'])
76
79
  }
77
80
 
81
+ updateCodeMirror = ({selectedFunctionType}) => {
82
+ if (selectedFunctionType === this.SANITY_FUNCTION_SCHEDULE) {
83
+ this.api.store.beforePayload.dispatch({
84
+ effects: editableCompartment.reconfigure(EditorView.editable.of(false)),
85
+ })
86
+ this.api.store.afterPayload.dispatch({
87
+ effects: editableCompartment.reconfigure(EditorView.editable.of(false)),
88
+ })
89
+ this.api.store.payload.dispatch({
90
+ effects: editableCompartment.reconfigure(EditorView.editable.of(false)),
91
+ })
92
+ } else {
93
+ this.api.store.beforePayload.dispatch({
94
+ effects: editableCompartment.reconfigure(EditorView.editable.of(true)),
95
+ })
96
+ this.api.store.afterPayload.dispatch({
97
+ effects: editableCompartment.reconfigure(EditorView.editable.of(true)),
98
+ })
99
+ this.api.store.payload.dispatch({
100
+ effects: editableCompartment.reconfigure(EditorView.editable.of(true)),
101
+ })
102
+ }
103
+ }
78
104
  updatePayload = ({document}) => {
79
105
  if (!document) return
80
106
 
@@ -93,8 +119,6 @@ class PayloadPanel extends ApiBaseElement {
93
119
  view.dispatch(transaction)
94
120
  }
95
121
  updateSelectedEvent = ({selectedEvent}) => {
96
- console.log('updateSelectedEvent', selectedEvent)
97
-
98
122
  const payloadContainer = this.shadowRoot.querySelector('#payloadContainer')
99
123
  const deltaPayloadContainer = this.shadowRoot.querySelector('#deltaPayloadContainer')
100
124
 
@@ -113,7 +137,12 @@ class PayloadPanel extends ApiBaseElement {
113
137
  function attachEditorView(parent) {
114
138
  return new EditorView({
115
139
  doc: '\n\n\n\n',
116
- extensions: [basicSetup, json(), sanityCodeMirrorTheme],
140
+ extensions: [
141
+ basicSetup,
142
+ json(),
143
+ sanityCodeMirrorTheme,
144
+ editableCompartment.of(EditorView.editable.of(false)),
145
+ ],
117
146
  parent,
118
147
  })
119
148
  }