@tinacms/app 0.0.0-61c45f4-20250123000522 → 0.0.0-623f8b7-20251210213020
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/CHANGELOG.md +257 -9
- package/index.html +1 -1
- package/package.json +13 -9
- package/src/App.tsx +24 -24
- package/src/Playground.tsx +56 -58
- package/src/dummy-client.ts +1 -1
- package/src/fields/rich-text/index.tsx +2 -2
- package/src/fields/rich-text/monaco/error-message.tsx +59 -59
- package/src/fields/rich-text/monaco/index.tsx +68 -74
- package/src/fields/rich-text/monaco/use-debounce.ts +8 -8
- package/src/global.css +3 -3
- package/src/index.css +24 -15
- package/src/lib/build-form.ts +24 -24
- package/src/lib/errors.tsx +7 -7
- package/src/lib/expand-query.ts +74 -69
- package/src/lib/graphql-reducer.ts +361 -277
- package/src/lib/types.ts +36 -33
- package/src/lib/util.ts +48 -53
- package/src/main.tsx +7 -7
- package/src/preflight.css +10 -10
- package/src/preview.tsx +12 -12
- package/src/vite-env.d.ts +3 -3
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import * as G from 'graphql'
|
|
3
|
-
import { getIn } from 'final-form'
|
|
4
|
-
import { z } from 'zod'
|
|
5
1
|
// @ts-expect-error
|
|
6
|
-
import schemaJson from 'SCHEMA_IMPORT'
|
|
7
|
-
import {
|
|
2
|
+
import schemaJson from 'SCHEMA_IMPORT';
|
|
3
|
+
import { getIn } from 'final-form';
|
|
4
|
+
import * as G from 'graphql';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { useSearchParams } from 'react-router-dom';
|
|
8
7
|
import {
|
|
8
|
+
Client,
|
|
9
|
+
Collection,
|
|
10
|
+
ErrorDialog,
|
|
9
11
|
Form,
|
|
10
|
-
|
|
12
|
+
FormOptions,
|
|
13
|
+
GlobalFormPlugin,
|
|
11
14
|
NAMER,
|
|
12
|
-
TinaSchema,
|
|
13
|
-
useCMS,
|
|
14
|
-
resolveField,
|
|
15
|
-
Collection,
|
|
16
15
|
Template,
|
|
16
|
+
TinaCMS,
|
|
17
17
|
TinaField,
|
|
18
|
-
|
|
19
|
-
FormOptions,
|
|
20
|
-
GlobalFormPlugin,
|
|
18
|
+
TinaSchema,
|
|
21
19
|
TinaState,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
resolveField,
|
|
21
|
+
useCMS,
|
|
22
|
+
} from 'tinacms';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
import { FormifyCallback, createForm, createGlobalForm } from './build-form';
|
|
25
|
+
import { showErrorModal } from './errors';
|
|
26
|
+
import { expandQuery, isConnectionType, isNodeType } from './expand-query';
|
|
25
27
|
import type {
|
|
26
|
-
PostMessage,
|
|
27
28
|
Payload,
|
|
28
|
-
|
|
29
|
+
PostMessage,
|
|
29
30
|
ResolvedDocument,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
import {
|
|
33
|
-
import { showErrorModal } from './errors'
|
|
31
|
+
SystemInfo,
|
|
32
|
+
} from './types';
|
|
33
|
+
import { getFormAndFieldNameFromMetadata } from './util';
|
|
34
34
|
|
|
35
35
|
const sysSchema = z.object({
|
|
36
36
|
breadcrumbs: z.array(z.string()),
|
|
@@ -45,19 +45,19 @@ const sysSchema = z.object({
|
|
|
45
45
|
collection: z.object({
|
|
46
46
|
name: z.string(),
|
|
47
47
|
slug: z.string(),
|
|
48
|
-
label: z.string(),
|
|
48
|
+
label: z.string().optional().nullable(),
|
|
49
49
|
path: z.string(),
|
|
50
50
|
format: z.string().optional().nullable(),
|
|
51
51
|
matches: z.string().optional().nullable(),
|
|
52
52
|
}),
|
|
53
|
-
})
|
|
53
|
+
});
|
|
54
54
|
|
|
55
55
|
const documentSchema: z.ZodType<ResolvedDocument> = z.object({
|
|
56
56
|
_internalValues: z.record(z.unknown()),
|
|
57
57
|
_internalSys: sysSchema,
|
|
58
|
-
})
|
|
58
|
+
});
|
|
59
59
|
|
|
60
|
-
const astNode = schemaJson as G.DocumentNode
|
|
60
|
+
const astNode = schemaJson as G.DocumentNode;
|
|
61
61
|
const astNodeWithMeta: G.DocumentNode = {
|
|
62
62
|
...astNode,
|
|
63
63
|
definitions: astNode.definitions.map((def) => {
|
|
@@ -103,7 +103,7 @@ const astNodeWithMeta: G.DocumentNode = {
|
|
|
103
103
|
},
|
|
104
104
|
},
|
|
105
105
|
],
|
|
106
|
-
}
|
|
106
|
+
};
|
|
107
107
|
}
|
|
108
108
|
if (def.kind === 'ObjectTypeDefinition') {
|
|
109
109
|
return {
|
|
@@ -147,68 +147,68 @@ const astNodeWithMeta: G.DocumentNode = {
|
|
|
147
147
|
},
|
|
148
148
|
},
|
|
149
149
|
],
|
|
150
|
-
}
|
|
150
|
+
};
|
|
151
151
|
}
|
|
152
|
-
return def
|
|
152
|
+
return def;
|
|
153
153
|
}),
|
|
154
|
-
}
|
|
155
|
-
const schema = G.buildASTSchema(astNode)
|
|
156
|
-
const schemaForResolver = G.buildASTSchema(astNodeWithMeta)
|
|
154
|
+
};
|
|
155
|
+
const schema = G.buildASTSchema(astNode);
|
|
156
|
+
const schemaForResolver = G.buildASTSchema(astNodeWithMeta);
|
|
157
157
|
|
|
158
158
|
const isRejected = (
|
|
159
159
|
input: PromiseSettledResult<unknown>
|
|
160
|
-
): input is PromiseRejectedResult => input.status === 'rejected'
|
|
160
|
+
): input is PromiseRejectedResult => input.status === 'rejected';
|
|
161
161
|
|
|
162
162
|
const isFulfilled = <T>(
|
|
163
163
|
input: PromiseSettledResult<T>
|
|
164
|
-
): input is PromiseFulfilledResult<T> => input.status === 'fulfilled'
|
|
164
|
+
): input is PromiseFulfilledResult<T> => input.status === 'fulfilled';
|
|
165
165
|
|
|
166
166
|
export const useGraphQLReducer = (
|
|
167
167
|
iframe: React.MutableRefObject<HTMLIFrameElement>,
|
|
168
168
|
url: string
|
|
169
169
|
) => {
|
|
170
|
-
const cms = useCMS()
|
|
171
|
-
const tinaSchema = cms.api.tina.schema as TinaSchema
|
|
172
|
-
const [payloads, setPayloads] = React.useState<Payload[]>([])
|
|
173
|
-
const [requestErrors, setRequestErrors] = React.useState<string[]>([])
|
|
174
|
-
const [searchParams, setSearchParams] = useSearchParams()
|
|
170
|
+
const cms = useCMS();
|
|
171
|
+
const tinaSchema = cms.api.tina.schema as TinaSchema;
|
|
172
|
+
const [payloads, setPayloads] = React.useState<Payload[]>([]);
|
|
173
|
+
const [requestErrors, setRequestErrors] = React.useState<string[]>([]);
|
|
174
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
175
175
|
const [results, setResults] = React.useState<
|
|
176
176
|
{
|
|
177
|
-
id: string
|
|
177
|
+
id: string;
|
|
178
178
|
data:
|
|
179
179
|
| {
|
|
180
|
-
[key: string]: any
|
|
180
|
+
[key: string]: any;
|
|
181
181
|
}
|
|
182
182
|
| null
|
|
183
|
-
| undefined
|
|
183
|
+
| undefined;
|
|
184
184
|
}[]
|
|
185
|
-
>([])
|
|
185
|
+
>([]);
|
|
186
186
|
const [documentsToResolve, setDocumentsToResolve] = React.useState<string[]>(
|
|
187
187
|
[]
|
|
188
|
-
)
|
|
188
|
+
);
|
|
189
189
|
const [resolvedDocuments, setResolvedDocuments] = React.useState<
|
|
190
190
|
ResolvedDocument[]
|
|
191
|
-
>([])
|
|
192
|
-
const [operationIndex, setOperationIndex] = React.useState(0)
|
|
191
|
+
>([]);
|
|
192
|
+
const [operationIndex, setOperationIndex] = React.useState(0);
|
|
193
193
|
|
|
194
|
-
const activeField = searchParams.get('active-field')
|
|
194
|
+
const activeField = searchParams.get('active-field');
|
|
195
195
|
|
|
196
196
|
React.useEffect(() => {
|
|
197
197
|
const run = async () => {
|
|
198
198
|
return Promise.all(
|
|
199
199
|
documentsToResolve.map(async (documentId) => {
|
|
200
|
-
return await getDocument(documentId, cms.api.tina)
|
|
200
|
+
return await getDocument(documentId, cms.api.tina);
|
|
201
201
|
})
|
|
202
|
-
)
|
|
203
|
-
}
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
204
|
if (documentsToResolve.length) {
|
|
205
205
|
run().then((docs) => {
|
|
206
|
-
setResolvedDocuments((resolvedDocs) => [...resolvedDocs, ...docs])
|
|
207
|
-
setDocumentsToResolve([])
|
|
208
|
-
setOperationIndex((i) => i + 1)
|
|
209
|
-
})
|
|
206
|
+
setResolvedDocuments((resolvedDocs) => [...resolvedDocs, ...docs]);
|
|
207
|
+
setDocumentsToResolve([]);
|
|
208
|
+
setOperationIndex((i) => i + 1);
|
|
209
|
+
});
|
|
210
210
|
}
|
|
211
|
-
}, [documentsToResolve.join('.')])
|
|
211
|
+
}, [documentsToResolve.join('.')]);
|
|
212
212
|
|
|
213
213
|
/**
|
|
214
214
|
* Note: since React runs effects twice in development this will run twice for a given query
|
|
@@ -216,39 +216,41 @@ export const useGraphQLReducer = (
|
|
|
216
216
|
*/
|
|
217
217
|
React.useEffect(() => {
|
|
218
218
|
const run = async () => {
|
|
219
|
-
setRequestErrors([])
|
|
219
|
+
setRequestErrors([]);
|
|
220
220
|
// gather the errors and display an error message containing each error unique message
|
|
221
221
|
return Promise.allSettled(
|
|
222
222
|
payloads.map(async (payload) => {
|
|
223
223
|
// This payload has already been expanded, skip it.
|
|
224
224
|
if (payload.expandedQuery) {
|
|
225
|
-
return payload
|
|
225
|
+
return payload;
|
|
226
226
|
} else {
|
|
227
|
-
const expandedPayload = await expandPayload(payload, cms)
|
|
228
|
-
processPayload(expandedPayload)
|
|
229
|
-
return expandedPayload
|
|
227
|
+
const expandedPayload = await expandPayload(payload, cms);
|
|
228
|
+
processPayload(expandedPayload);
|
|
229
|
+
return expandedPayload;
|
|
230
230
|
}
|
|
231
231
|
})
|
|
232
|
-
)
|
|
233
|
-
}
|
|
232
|
+
);
|
|
233
|
+
};
|
|
234
234
|
if (payloads.length) {
|
|
235
235
|
run().then((updatedPayloads) => {
|
|
236
|
-
setPayloads(updatedPayloads.filter(isFulfilled).map((p) => p.value))
|
|
236
|
+
setPayloads(updatedPayloads.filter(isFulfilled).map((p) => p.value));
|
|
237
237
|
setRequestErrors(
|
|
238
238
|
updatedPayloads.filter(isRejected).map((p) => String(p.reason))
|
|
239
|
-
)
|
|
240
|
-
})
|
|
239
|
+
);
|
|
240
|
+
});
|
|
241
241
|
}
|
|
242
|
-
}, [JSON.stringify(payloads), cms])
|
|
242
|
+
}, [JSON.stringify(payloads), cms]);
|
|
243
243
|
|
|
244
244
|
const processPayload = React.useCallback(
|
|
245
245
|
(payload: Payload) => {
|
|
246
|
-
const { expandedQueryForResolver, variables, expandedData } = payload
|
|
246
|
+
const { expandedQueryForResolver, variables, expandedData } = payload;
|
|
247
247
|
if (!expandedQueryForResolver || !expandedData) {
|
|
248
|
-
throw new Error(
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Unable to process payload which has not been expanded`
|
|
250
|
+
);
|
|
249
251
|
}
|
|
250
|
-
const formListItems: TinaState['formLists'][number]['items'] = []
|
|
251
|
-
const formIds: string[] = []
|
|
252
|
+
const formListItems: TinaState['formLists'][number]['items'] = [];
|
|
253
|
+
const formIds: string[] = [];
|
|
252
254
|
|
|
253
255
|
const result = G.graphqlSync({
|
|
254
256
|
schema: schemaForResolver,
|
|
@@ -256,7 +258,7 @@ export const useGraphQLReducer = (
|
|
|
256
258
|
variableValues: variables,
|
|
257
259
|
rootValue: expandedData,
|
|
258
260
|
fieldResolver: (source, args, context, info) => {
|
|
259
|
-
const fieldName = info.fieldName
|
|
261
|
+
const fieldName = info.fieldName;
|
|
260
262
|
/**
|
|
261
263
|
* Since the `source` for this resolver is the query that
|
|
262
264
|
* ran before passing it into `useTina`, we need to take aliases
|
|
@@ -265,35 +267,35 @@ export const useGraphQLReducer = (
|
|
|
265
267
|
* solution as the `value` gets overwritten depending on the alias
|
|
266
268
|
* query.
|
|
267
269
|
*/
|
|
268
|
-
const aliases: string[] = []
|
|
270
|
+
const aliases: string[] = [];
|
|
269
271
|
info.fieldNodes.forEach((fieldNode) => {
|
|
270
272
|
if (fieldNode.alias) {
|
|
271
|
-
aliases.push(fieldNode.alias.value)
|
|
273
|
+
aliases.push(fieldNode.alias.value);
|
|
272
274
|
}
|
|
273
|
-
})
|
|
274
|
-
let value = source[fieldName] as unknown
|
|
275
|
+
});
|
|
276
|
+
let value = source[fieldName] as unknown;
|
|
275
277
|
aliases.forEach((alias) => {
|
|
276
|
-
const aliasValue = source[alias]
|
|
278
|
+
const aliasValue = source[alias];
|
|
277
279
|
if (aliasValue) {
|
|
278
|
-
value = aliasValue
|
|
280
|
+
value = aliasValue;
|
|
279
281
|
}
|
|
280
|
-
})
|
|
282
|
+
});
|
|
281
283
|
if (fieldName === '_sys') {
|
|
282
|
-
return source._internalSys
|
|
284
|
+
return source._internalSys;
|
|
283
285
|
}
|
|
284
286
|
if (fieldName === '_values') {
|
|
285
|
-
return source._internalValues
|
|
287
|
+
return source._internalValues;
|
|
286
288
|
}
|
|
287
289
|
if (info.fieldName === '_content_source') {
|
|
288
|
-
const pathArray = G.responsePathAsArray(info.path)
|
|
290
|
+
const pathArray = G.responsePathAsArray(info.path);
|
|
289
291
|
return {
|
|
290
292
|
queryId: payload.id,
|
|
291
293
|
path: pathArray.slice(0, pathArray.length - 1),
|
|
292
|
-
}
|
|
294
|
+
};
|
|
293
295
|
}
|
|
294
296
|
if (info.fieldName === '_tina_metadata') {
|
|
295
297
|
if (value) {
|
|
296
|
-
return value
|
|
298
|
+
return value;
|
|
297
299
|
}
|
|
298
300
|
// TODO: ensure all fields that have _tina_metadata
|
|
299
301
|
// actually need it
|
|
@@ -301,77 +303,80 @@ export const useGraphQLReducer = (
|
|
|
301
303
|
id: null,
|
|
302
304
|
fields: [],
|
|
303
305
|
prefix: '',
|
|
304
|
-
}
|
|
306
|
+
};
|
|
305
307
|
}
|
|
308
|
+
|
|
306
309
|
if (isConnectionType(info.returnType)) {
|
|
307
|
-
const name = G.getNamedType(info.returnType).name
|
|
310
|
+
const name = G.getNamedType(info.returnType).name;
|
|
308
311
|
const connectionCollection = tinaSchema
|
|
309
312
|
.getCollections()
|
|
310
313
|
.find((collection) => {
|
|
311
314
|
const collectionName = NAMER.referenceConnectionType(
|
|
312
315
|
collection.namespace
|
|
313
|
-
)
|
|
316
|
+
);
|
|
314
317
|
if (collectionName === name) {
|
|
315
|
-
return true
|
|
318
|
+
return true;
|
|
316
319
|
}
|
|
317
|
-
return false
|
|
318
|
-
})
|
|
320
|
+
return false;
|
|
321
|
+
});
|
|
319
322
|
if (connectionCollection) {
|
|
320
323
|
formListItems.push({
|
|
321
324
|
type: 'list',
|
|
322
325
|
label: connectionCollection.label || connectionCollection.name,
|
|
323
|
-
})
|
|
326
|
+
});
|
|
324
327
|
}
|
|
325
328
|
}
|
|
326
329
|
if (isNodeType(info.returnType)) {
|
|
327
330
|
if (!value) {
|
|
328
|
-
return
|
|
331
|
+
return;
|
|
329
332
|
}
|
|
330
|
-
let resolvedDocument: ResolvedDocument
|
|
333
|
+
let resolvedDocument: ResolvedDocument;
|
|
331
334
|
// This is a reference from another form
|
|
332
335
|
if (typeof value === 'string') {
|
|
333
336
|
const valueFromSetup = getIn(
|
|
334
337
|
expandedData,
|
|
335
338
|
G.responsePathAsArray(info.path).join('.')
|
|
336
|
-
)
|
|
339
|
+
);
|
|
337
340
|
const maybeResolvedDocument = resolvedDocuments.find(
|
|
338
341
|
(doc) => doc._internalSys.path === value
|
|
339
|
-
)
|
|
342
|
+
);
|
|
343
|
+
|
|
340
344
|
// If we already have this document, use it.
|
|
341
345
|
if (maybeResolvedDocument) {
|
|
342
|
-
resolvedDocument = maybeResolvedDocument
|
|
346
|
+
resolvedDocument = maybeResolvedDocument;
|
|
343
347
|
} else if (valueFromSetup) {
|
|
344
348
|
// Else, even though in this context the value is a string because it's
|
|
345
349
|
// resolved from a parent form, if the reference hasn't changed
|
|
346
350
|
// from when we ran the setup query, we can avoid a data fetch
|
|
347
351
|
// here and just grab it from the response
|
|
348
352
|
const maybeResolvedDocument =
|
|
349
|
-
documentSchema.parse(valueFromSetup)
|
|
353
|
+
documentSchema.parse(valueFromSetup);
|
|
354
|
+
|
|
350
355
|
if (maybeResolvedDocument._internalSys.path === value) {
|
|
351
|
-
resolvedDocument = maybeResolvedDocument
|
|
356
|
+
resolvedDocument = maybeResolvedDocument;
|
|
352
357
|
} else {
|
|
353
|
-
throw new NoFormError(`No form found`, value)
|
|
358
|
+
throw new NoFormError(`No form found`, value);
|
|
354
359
|
}
|
|
355
360
|
} else {
|
|
356
|
-
throw new NoFormError(`No form found`, value)
|
|
361
|
+
throw new NoFormError(`No form found`, value);
|
|
357
362
|
}
|
|
358
363
|
} else {
|
|
359
|
-
resolvedDocument = documentSchema.parse(value)
|
|
364
|
+
resolvedDocument = documentSchema.parse(value);
|
|
360
365
|
}
|
|
361
|
-
const id = resolvedDocument._internalSys.path
|
|
362
|
-
formIds.push(id)
|
|
366
|
+
const id = resolvedDocument._internalSys.path;
|
|
367
|
+
formIds.push(id);
|
|
363
368
|
const existingForm = cms.state.forms.find(
|
|
364
369
|
(f) => f.tinaForm.id === id
|
|
365
|
-
)
|
|
370
|
+
);
|
|
366
371
|
|
|
367
|
-
const pathArray = G.responsePathAsArray(info.path)
|
|
368
|
-
const pathString = pathArray.join('.')
|
|
372
|
+
const pathArray = G.responsePathAsArray(info.path);
|
|
373
|
+
const pathString = pathArray.join('.');
|
|
369
374
|
const ancestors = formListItems.filter((item) => {
|
|
370
375
|
if (item.type === 'document') {
|
|
371
|
-
return pathString.startsWith(item.path)
|
|
376
|
+
return pathString.startsWith(item.path);
|
|
372
377
|
}
|
|
373
|
-
})
|
|
374
|
-
const parent = ancestors[ancestors.length - 1]
|
|
378
|
+
});
|
|
379
|
+
const parent = ancestors[ancestors.length - 1];
|
|
375
380
|
if (parent) {
|
|
376
381
|
if (parent.type === 'document') {
|
|
377
382
|
parent.subItems.push({
|
|
@@ -379,7 +384,7 @@ export const useGraphQLReducer = (
|
|
|
379
384
|
path: pathString,
|
|
380
385
|
formId: id,
|
|
381
386
|
subItems: [],
|
|
382
|
-
})
|
|
387
|
+
});
|
|
383
388
|
}
|
|
384
389
|
} else {
|
|
385
390
|
formListItems.push({
|
|
@@ -387,7 +392,7 @@ export const useGraphQLReducer = (
|
|
|
387
392
|
path: pathString,
|
|
388
393
|
formId: id,
|
|
389
394
|
subItems: [],
|
|
390
|
-
})
|
|
395
|
+
});
|
|
391
396
|
}
|
|
392
397
|
|
|
393
398
|
if (!existingForm) {
|
|
@@ -396,65 +401,65 @@ export const useGraphQLReducer = (
|
|
|
396
401
|
tinaSchema,
|
|
397
402
|
payloadId: payload.id,
|
|
398
403
|
cms,
|
|
399
|
-
})
|
|
404
|
+
});
|
|
400
405
|
form.subscribe(
|
|
401
406
|
() => {
|
|
402
|
-
setOperationIndex((i) => i + 1)
|
|
407
|
+
setOperationIndex((i) => i + 1);
|
|
403
408
|
},
|
|
404
409
|
{ values: true }
|
|
405
|
-
)
|
|
410
|
+
);
|
|
406
411
|
return resolveDocument(
|
|
407
412
|
resolvedDocument,
|
|
408
413
|
template,
|
|
409
414
|
form,
|
|
410
415
|
pathString
|
|
411
|
-
)
|
|
416
|
+
);
|
|
412
417
|
} else {
|
|
413
|
-
existingForm.tinaForm.addQuery(payload.id)
|
|
418
|
+
existingForm.tinaForm.addQuery(payload.id);
|
|
414
419
|
const { template } = getTemplateForDocument(
|
|
415
420
|
resolvedDocument,
|
|
416
421
|
tinaSchema
|
|
417
|
-
)
|
|
418
|
-
existingForm.tinaForm.addQuery(payload.id)
|
|
422
|
+
);
|
|
423
|
+
existingForm.tinaForm.addQuery(payload.id);
|
|
419
424
|
return resolveDocument(
|
|
420
425
|
resolvedDocument,
|
|
421
426
|
template,
|
|
422
427
|
existingForm.tinaForm,
|
|
423
428
|
pathString
|
|
424
|
-
)
|
|
429
|
+
);
|
|
425
430
|
}
|
|
426
431
|
}
|
|
427
|
-
return value
|
|
432
|
+
return value;
|
|
428
433
|
},
|
|
429
|
-
})
|
|
434
|
+
});
|
|
430
435
|
if (result.errors) {
|
|
431
436
|
result.errors.forEach((error) => {
|
|
432
437
|
if (
|
|
433
438
|
error instanceof G.GraphQLError &&
|
|
434
439
|
error.originalError instanceof NoFormError
|
|
435
440
|
) {
|
|
436
|
-
const id = error.originalError.id
|
|
441
|
+
const id = error.originalError.id;
|
|
437
442
|
setDocumentsToResolve((docs) => [
|
|
438
443
|
...docs.filter((doc) => doc !== id),
|
|
439
444
|
id,
|
|
440
|
-
])
|
|
445
|
+
]);
|
|
441
446
|
} else {
|
|
442
|
-
console.log(error)
|
|
447
|
+
console.log(error);
|
|
443
448
|
// throw new Error(
|
|
444
449
|
// `Error processing value change, please contact support`
|
|
445
450
|
// )
|
|
446
451
|
}
|
|
447
|
-
})
|
|
452
|
+
});
|
|
448
453
|
} else {
|
|
449
454
|
if (result.data) {
|
|
450
455
|
setResults((results) => [
|
|
451
456
|
...results.filter((result) => result.id !== payload.id),
|
|
452
457
|
{ id: payload.id, data: result.data },
|
|
453
|
-
])
|
|
458
|
+
]);
|
|
454
459
|
}
|
|
455
460
|
if (activeField) {
|
|
456
|
-
setSearchParams({})
|
|
457
|
-
const [queryId, eventFieldName] = activeField.split('---')
|
|
461
|
+
setSearchParams({});
|
|
462
|
+
const [queryId, eventFieldName] = activeField.split('---');
|
|
458
463
|
if (queryId === payload.id) {
|
|
459
464
|
if (result?.data) {
|
|
460
465
|
cms.dispatch({
|
|
@@ -463,19 +468,19 @@ export const useGraphQLReducer = (
|
|
|
463
468
|
result.data,
|
|
464
469
|
eventFieldName
|
|
465
470
|
),
|
|
466
|
-
})
|
|
471
|
+
});
|
|
467
472
|
}
|
|
468
473
|
cms.dispatch({
|
|
469
474
|
type: 'sidebar:set-display-state',
|
|
470
475
|
value: 'openOrFull',
|
|
471
|
-
})
|
|
476
|
+
});
|
|
472
477
|
}
|
|
473
478
|
}
|
|
474
479
|
iframe.current?.contentWindow?.postMessage({
|
|
475
480
|
type: 'updateData',
|
|
476
481
|
id: payload.id,
|
|
477
482
|
data: result.data,
|
|
478
|
-
})
|
|
483
|
+
});
|
|
479
484
|
}
|
|
480
485
|
cms.dispatch({
|
|
481
486
|
type: 'form-lists:add',
|
|
@@ -485,57 +490,96 @@ export const useGraphQLReducer = (
|
|
|
485
490
|
items: formListItems,
|
|
486
491
|
formIds,
|
|
487
492
|
},
|
|
488
|
-
})
|
|
493
|
+
});
|
|
489
494
|
},
|
|
490
495
|
[
|
|
491
496
|
resolvedDocuments.map((doc) => doc._internalSys.path).join('.'),
|
|
492
497
|
activeField,
|
|
493
498
|
]
|
|
494
|
-
)
|
|
499
|
+
);
|
|
495
500
|
|
|
496
501
|
const handleMessage = React.useCallback(
|
|
497
502
|
(event: MessageEvent<PostMessage>) => {
|
|
503
|
+
if (event.data.type === 'user-select-form') {
|
|
504
|
+
cms.dispatch({
|
|
505
|
+
type: 'forms:set-active-form-id',
|
|
506
|
+
value: event.data.formId,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
498
510
|
if (event?.data?.type === 'quick-edit') {
|
|
499
511
|
cms.dispatch({
|
|
500
512
|
type: 'set-quick-editing-supported',
|
|
501
513
|
value: event.data.value,
|
|
502
|
-
})
|
|
514
|
+
});
|
|
503
515
|
iframe.current?.contentWindow?.postMessage({
|
|
504
516
|
type: 'quickEditEnabled',
|
|
505
517
|
value: cms.state.sidebarDisplayState === 'open',
|
|
506
|
-
})
|
|
518
|
+
});
|
|
507
519
|
}
|
|
508
520
|
if (event?.data?.type === 'isEditMode') {
|
|
509
521
|
iframe?.current?.contentWindow?.postMessage({
|
|
510
522
|
type: 'tina:editMode',
|
|
511
|
-
})
|
|
523
|
+
});
|
|
512
524
|
}
|
|
513
525
|
if (event.data.type === 'field:selected') {
|
|
514
|
-
const [queryId, eventFieldName] = event.data.fieldName.split('---')
|
|
515
|
-
const result = results.find((res) => res.id === queryId)
|
|
526
|
+
const [queryId, eventFieldName] = event.data.fieldName.split('---');
|
|
527
|
+
const result = results.find((res) => res.id === queryId);
|
|
516
528
|
if (result?.data) {
|
|
529
|
+
const { formId, fieldName } = getFormAndFieldNameFromMetadata(
|
|
530
|
+
result.data,
|
|
531
|
+
eventFieldName
|
|
532
|
+
);
|
|
517
533
|
cms.dispatch({
|
|
518
534
|
type: 'forms:set-active-field-name',
|
|
519
|
-
value:
|
|
520
|
-
})
|
|
535
|
+
value: { formId: formId, fieldName: fieldName },
|
|
536
|
+
});
|
|
537
|
+
cms.events.dispatch({
|
|
538
|
+
...event.data,
|
|
539
|
+
type: 'field:focus',
|
|
540
|
+
});
|
|
521
541
|
}
|
|
522
542
|
cms.dispatch({
|
|
523
543
|
type: 'sidebar:set-display-state',
|
|
524
544
|
value: 'openOrFull',
|
|
525
|
-
})
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
if (event.data.type === 'field:hovered') {
|
|
548
|
+
if (event.data.fieldName) {
|
|
549
|
+
const [queryId, eventFieldName] = event.data.fieldName.split('---');
|
|
550
|
+
const result = results.find((res) => res.id === queryId);
|
|
551
|
+
if (result?.data) {
|
|
552
|
+
const fieldData = getFormAndFieldNameFromMetadata(
|
|
553
|
+
result.data,
|
|
554
|
+
eventFieldName
|
|
555
|
+
);
|
|
556
|
+
cms.dispatch({
|
|
557
|
+
type: 'forms:set-hovered-field-name',
|
|
558
|
+
value: fieldData,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
} else {
|
|
562
|
+
// Clear hover state when fieldName is null
|
|
563
|
+
cms.forms.all().forEach((form) => {
|
|
564
|
+
cms.dispatch({
|
|
565
|
+
type: 'forms:set-hovered-field-name',
|
|
566
|
+
value: { formId: form.id, fieldName: null },
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
}
|
|
526
570
|
}
|
|
527
571
|
if (event.data.type === 'close') {
|
|
528
|
-
const payloadSchema = z.object({ id: z.string() })
|
|
529
|
-
const { id } = payloadSchema.parse(event.data)
|
|
572
|
+
const payloadSchema = z.object({ id: z.string() });
|
|
573
|
+
const { id } = payloadSchema.parse(event.data);
|
|
530
574
|
setPayloads((previous) =>
|
|
531
575
|
previous.filter((payload) => payload.id !== id)
|
|
532
|
-
)
|
|
533
|
-
setResults((previous) => previous.filter((result) => result.id !== id))
|
|
576
|
+
);
|
|
577
|
+
setResults((previous) => previous.filter((result) => result.id !== id));
|
|
534
578
|
cms.forms.all().map((form) => {
|
|
535
|
-
form.removeQuery(id)
|
|
536
|
-
})
|
|
537
|
-
cms.removeOrphanedForms()
|
|
538
|
-
cms.dispatch({ type: 'form-lists:remove', value: id })
|
|
579
|
+
form.removeQuery(id);
|
|
580
|
+
});
|
|
581
|
+
cms.removeOrphanedForms();
|
|
582
|
+
cms.dispatch({ type: 'form-lists:remove', value: id });
|
|
539
583
|
}
|
|
540
584
|
if (event.data.type === 'open') {
|
|
541
585
|
const payloadSchema = z.object({
|
|
@@ -543,60 +587,95 @@ export const useGraphQLReducer = (
|
|
|
543
587
|
query: z.string(),
|
|
544
588
|
variables: z.record(z.unknown()),
|
|
545
589
|
data: z.record(z.unknown()),
|
|
546
|
-
})
|
|
547
|
-
const payload = payloadSchema.parse(event.data)
|
|
590
|
+
});
|
|
591
|
+
const payload = payloadSchema.parse(event.data);
|
|
548
592
|
setPayloads((payloads) => [
|
|
549
593
|
...payloads.filter(({ id }) => id !== payload.id),
|
|
550
594
|
payload,
|
|
551
|
-
])
|
|
595
|
+
]);
|
|
552
596
|
}
|
|
597
|
+
// TODO: This is causing a webpack HMR issue - look into refactoring this logic
|
|
598
|
+
// if (event.data.type === 'url-changed') {
|
|
599
|
+
// console.log('[EVENT_TRIGGERED] url-changed: ', event);
|
|
600
|
+
// cms.dispatch({
|
|
601
|
+
// type: 'sidebar:set-loading-state',
|
|
602
|
+
// value: true,
|
|
603
|
+
// });
|
|
604
|
+
// }
|
|
553
605
|
},
|
|
554
606
|
[cms, JSON.stringify(results)]
|
|
555
|
-
)
|
|
607
|
+
);
|
|
556
608
|
|
|
557
609
|
React.useEffect(() => {
|
|
558
610
|
payloads.forEach((payload) => {
|
|
559
611
|
if (payload.expandedData) {
|
|
560
|
-
processPayload(payload)
|
|
612
|
+
processPayload(payload);
|
|
561
613
|
}
|
|
562
|
-
})
|
|
563
|
-
}, [operationIndex])
|
|
614
|
+
});
|
|
615
|
+
}, [operationIndex]);
|
|
564
616
|
|
|
565
617
|
React.useEffect(() => {
|
|
566
618
|
return () => {
|
|
567
|
-
setPayloads([])
|
|
568
|
-
setResults([])
|
|
569
|
-
cms.removeAllForms()
|
|
570
|
-
cms.dispatch({ type: 'form-lists:clear' })
|
|
571
|
-
}
|
|
572
|
-
}, [url])
|
|
619
|
+
setPayloads([]);
|
|
620
|
+
setResults([]);
|
|
621
|
+
cms.removeAllForms();
|
|
622
|
+
cms.dispatch({ type: 'form-lists:clear' });
|
|
623
|
+
};
|
|
624
|
+
}, [url]);
|
|
573
625
|
|
|
574
626
|
React.useEffect(() => {
|
|
575
627
|
iframe.current?.contentWindow?.postMessage({
|
|
576
628
|
type: 'quickEditEnabled',
|
|
577
629
|
value: cms.state.sidebarDisplayState === 'open',
|
|
578
|
-
})
|
|
579
|
-
}, [cms.state.sidebarDisplayState])
|
|
630
|
+
});
|
|
631
|
+
}, [cms.state.sidebarDisplayState]);
|
|
632
|
+
|
|
633
|
+
// Compute the active field name to send to iframe
|
|
634
|
+
const activeFieldName = React.useMemo(() => {
|
|
635
|
+
const activeForm = cms.state.forms.find(
|
|
636
|
+
(form: any) => form.tinaForm.id === cms.state.activeFormId
|
|
637
|
+
);
|
|
638
|
+
if (!activeForm) {
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
const fieldName = activeForm.activeFieldName;
|
|
642
|
+
if (fieldName === null) {
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
const queries = activeForm.tinaForm.queries;
|
|
646
|
+
if (queries && queries.length > 0) {
|
|
647
|
+
const queryId = queries[queries.length - 1];
|
|
648
|
+
return `${queryId}---${fieldName}`;
|
|
649
|
+
}
|
|
650
|
+
return null;
|
|
651
|
+
}, [cms.state.forms, cms.state.activeFormId]);
|
|
652
|
+
|
|
653
|
+
React.useEffect(() => {
|
|
654
|
+
iframe.current?.contentWindow?.postMessage({
|
|
655
|
+
type: 'field:set-focused',
|
|
656
|
+
fieldName: activeFieldName,
|
|
657
|
+
});
|
|
658
|
+
}, [activeFieldName, iframe]);
|
|
580
659
|
|
|
581
660
|
React.useEffect(() => {
|
|
582
|
-
cms.dispatch({ type: 'set-edit-mode', value: 'visual' })
|
|
661
|
+
cms.dispatch({ type: 'set-edit-mode', value: 'visual' });
|
|
583
662
|
if (iframe) {
|
|
584
|
-
window.addEventListener('message', handleMessage)
|
|
663
|
+
window.addEventListener('message', handleMessage);
|
|
585
664
|
}
|
|
586
665
|
|
|
587
666
|
return () => {
|
|
588
|
-
window.removeEventListener('message', handleMessage)
|
|
589
|
-
cms.removeAllForms()
|
|
590
|
-
cms.dispatch({ type: 'set-edit-mode', value: 'basic' })
|
|
591
|
-
}
|
|
592
|
-
}, [iframe.current, JSON.stringify(results)])
|
|
667
|
+
window.removeEventListener('message', handleMessage);
|
|
668
|
+
cms.removeAllForms();
|
|
669
|
+
cms.dispatch({ type: 'set-edit-mode', value: 'basic' });
|
|
670
|
+
};
|
|
671
|
+
}, [iframe.current, JSON.stringify(results)]);
|
|
593
672
|
|
|
594
673
|
React.useEffect(() => {
|
|
595
674
|
if (requestErrors.length) {
|
|
596
|
-
showErrorModal('Unexpected error querying content', requestErrors, cms)
|
|
675
|
+
showErrorModal('Unexpected error querying content', requestErrors, cms);
|
|
597
676
|
}
|
|
598
|
-
}, [requestErrors])
|
|
599
|
-
}
|
|
677
|
+
}, [requestErrors]);
|
|
678
|
+
};
|
|
600
679
|
|
|
601
680
|
const onSubmit = async (
|
|
602
681
|
collection: Collection<true>,
|
|
@@ -604,7 +683,7 @@ const onSubmit = async (
|
|
|
604
683
|
payload: Record<string, unknown>,
|
|
605
684
|
cms: TinaCMS
|
|
606
685
|
) => {
|
|
607
|
-
const tinaSchema = cms.api.tina.schema
|
|
686
|
+
const tinaSchema = cms.api.tina.schema;
|
|
608
687
|
try {
|
|
609
688
|
const mutationString = `#graphql
|
|
610
689
|
mutation UpdateDocument($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) {
|
|
@@ -612,7 +691,7 @@ const onSubmit = async (
|
|
|
612
691
|
__typename
|
|
613
692
|
}
|
|
614
693
|
}
|
|
615
|
-
|
|
694
|
+
`;
|
|
616
695
|
|
|
617
696
|
await cms.api.tina.request(mutationString, {
|
|
618
697
|
variables: {
|
|
@@ -620,8 +699,8 @@ const onSubmit = async (
|
|
|
620
699
|
relativePath: relativePath,
|
|
621
700
|
params: tinaSchema.transformPayload(collection.name, payload),
|
|
622
701
|
},
|
|
623
|
-
})
|
|
624
|
-
cms.alerts.success('Document saved!')
|
|
702
|
+
});
|
|
703
|
+
cms.alerts.success('Document saved!');
|
|
625
704
|
} catch (e) {
|
|
626
705
|
cms.alerts.error(() =>
|
|
627
706
|
ErrorDialog({
|
|
@@ -629,12 +708,12 @@ const onSubmit = async (
|
|
|
629
708
|
message: 'Tina caught an error while updating the page',
|
|
630
709
|
error: e,
|
|
631
710
|
})
|
|
632
|
-
)
|
|
633
|
-
console.error(e)
|
|
711
|
+
);
|
|
712
|
+
console.error(e);
|
|
634
713
|
}
|
|
635
|
-
}
|
|
714
|
+
};
|
|
636
715
|
|
|
637
|
-
type Path = (string | number)[]
|
|
716
|
+
type Path = (string | number)[];
|
|
638
717
|
|
|
639
718
|
const resolveDocument = (
|
|
640
719
|
doc: ResolvedDocument,
|
|
@@ -643,20 +722,20 @@ const resolveDocument = (
|
|
|
643
722
|
pathToDocument: string
|
|
644
723
|
): ResolvedDocument => {
|
|
645
724
|
// @ts-ignore AnyField and TinaField don't mix
|
|
646
|
-
const fields = form.fields as TinaField<true>[]
|
|
647
|
-
const id = doc._internalSys.path
|
|
648
|
-
const path: Path = []
|
|
725
|
+
const fields = form.fields as TinaField<true>[];
|
|
726
|
+
const id = doc._internalSys.path;
|
|
727
|
+
const path: Path = [];
|
|
649
728
|
const formValues = resolveFormValue({
|
|
650
729
|
fields: fields,
|
|
651
730
|
values: form.values,
|
|
652
731
|
path,
|
|
653
732
|
id,
|
|
654
733
|
pathToDocument,
|
|
655
|
-
})
|
|
656
|
-
const metadataFields: Record<string, string> = {}
|
|
734
|
+
});
|
|
735
|
+
const metadataFields: Record<string, string> = {};
|
|
657
736
|
Object.keys(formValues).forEach((key) => {
|
|
658
|
-
metadataFields[key] = [...path, key].join('.')
|
|
659
|
-
})
|
|
737
|
+
metadataFields[key] = [...path, key].join('.');
|
|
738
|
+
});
|
|
660
739
|
|
|
661
740
|
return {
|
|
662
741
|
...formValues,
|
|
@@ -672,8 +751,8 @@ const resolveDocument = (
|
|
|
672
751
|
_internalSys: doc._internalSys,
|
|
673
752
|
_internalValues: doc._internalValues,
|
|
674
753
|
__typename: NAMER.dataTypeName(template.namespace),
|
|
675
|
-
}
|
|
676
|
-
}
|
|
754
|
+
};
|
|
755
|
+
};
|
|
677
756
|
|
|
678
757
|
const resolveFormValue = <T extends Record<string, unknown>>({
|
|
679
758
|
fields,
|
|
@@ -683,21 +762,21 @@ const resolveFormValue = <T extends Record<string, unknown>>({
|
|
|
683
762
|
pathToDocument,
|
|
684
763
|
}: // tinaSchema,
|
|
685
764
|
{
|
|
686
|
-
fields: TinaField<true>[]
|
|
687
|
-
values: T
|
|
688
|
-
path: Path
|
|
689
|
-
id: string
|
|
690
|
-
pathToDocument: string
|
|
765
|
+
fields: TinaField<true>[];
|
|
766
|
+
values: T;
|
|
767
|
+
path: Path;
|
|
768
|
+
id: string;
|
|
769
|
+
pathToDocument: string;
|
|
691
770
|
// tinaSchema: TinaSchema
|
|
692
771
|
}): T & { __typename?: string } => {
|
|
693
|
-
const accum: Record<string, unknown> = {}
|
|
772
|
+
const accum: Record<string, unknown> = {};
|
|
694
773
|
fields.forEach((field) => {
|
|
695
|
-
const v = values[field.name]
|
|
774
|
+
const v = values[field.name];
|
|
696
775
|
if (typeof v === 'undefined') {
|
|
697
|
-
return
|
|
776
|
+
return;
|
|
698
777
|
}
|
|
699
778
|
if (v === null) {
|
|
700
|
-
return
|
|
779
|
+
return;
|
|
701
780
|
}
|
|
702
781
|
accum[field.name] = resolveFieldValue({
|
|
703
782
|
field,
|
|
@@ -705,10 +784,10 @@ const resolveFormValue = <T extends Record<string, unknown>>({
|
|
|
705
784
|
path,
|
|
706
785
|
id,
|
|
707
786
|
pathToDocument,
|
|
708
|
-
})
|
|
709
|
-
})
|
|
710
|
-
return accum as T & { __typename?: string }
|
|
711
|
-
}
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
return accum as T & { __typename?: string };
|
|
790
|
+
};
|
|
712
791
|
const resolveFieldValue = ({
|
|
713
792
|
field,
|
|
714
793
|
value,
|
|
@@ -716,11 +795,11 @@ const resolveFieldValue = ({
|
|
|
716
795
|
id,
|
|
717
796
|
pathToDocument,
|
|
718
797
|
}: {
|
|
719
|
-
field: TinaField<true
|
|
720
|
-
value: unknown
|
|
721
|
-
path: Path
|
|
722
|
-
id: string
|
|
723
|
-
pathToDocument: string
|
|
798
|
+
field: TinaField<true>;
|
|
799
|
+
value: unknown;
|
|
800
|
+
path: Path;
|
|
801
|
+
id: string;
|
|
802
|
+
pathToDocument: string;
|
|
724
803
|
}) => {
|
|
725
804
|
switch (field.type) {
|
|
726
805
|
case 'object': {
|
|
@@ -728,15 +807,17 @@ const resolveFieldValue = ({
|
|
|
728
807
|
if (field.list) {
|
|
729
808
|
if (Array.isArray(value)) {
|
|
730
809
|
return value.map((item, index) => {
|
|
731
|
-
const template = field.templates[item._template]
|
|
810
|
+
const template = field.templates[item._template];
|
|
732
811
|
if (typeof template === 'string') {
|
|
733
|
-
throw new Error('Global templates not supported')
|
|
812
|
+
throw new Error('Global templates not supported');
|
|
734
813
|
}
|
|
735
|
-
const nextPath = [...path, field.name, index]
|
|
736
|
-
const metadataFields: Record<string, string> = {}
|
|
814
|
+
const nextPath = [...path, field.name, index];
|
|
815
|
+
const metadataFields: Record<string, string> = {};
|
|
737
816
|
template.fields.forEach((field) => {
|
|
738
|
-
metadataFields[field.name] = [...nextPath, field.name].join(
|
|
739
|
-
|
|
817
|
+
metadataFields[field.name] = [...nextPath, field.name].join(
|
|
818
|
+
'.'
|
|
819
|
+
);
|
|
820
|
+
});
|
|
740
821
|
return {
|
|
741
822
|
__typename: NAMER.dataTypeName(template.namespace),
|
|
742
823
|
_tina_metadata: {
|
|
@@ -752,29 +833,29 @@ const resolveFieldValue = ({
|
|
|
752
833
|
id,
|
|
753
834
|
pathToDocument,
|
|
754
835
|
}),
|
|
755
|
-
}
|
|
756
|
-
})
|
|
836
|
+
};
|
|
837
|
+
});
|
|
757
838
|
}
|
|
758
839
|
} else {
|
|
759
840
|
// not implemented
|
|
760
841
|
}
|
|
761
842
|
}
|
|
762
843
|
|
|
763
|
-
const templateFields = field.fields
|
|
844
|
+
const templateFields = field.fields;
|
|
764
845
|
if (typeof templateFields === 'string') {
|
|
765
|
-
throw new Error('Global templates not supported')
|
|
846
|
+
throw new Error('Global templates not supported');
|
|
766
847
|
}
|
|
767
848
|
if (!templateFields) {
|
|
768
|
-
throw new Error(`Expected to find sub-fields on field ${field.name}`)
|
|
849
|
+
throw new Error(`Expected to find sub-fields on field ${field.name}`);
|
|
769
850
|
}
|
|
770
851
|
if (field.list) {
|
|
771
852
|
if (Array.isArray(value)) {
|
|
772
853
|
return value.map((item, index) => {
|
|
773
|
-
const nextPath = [...path, field.name, index]
|
|
774
|
-
const metadataFields: Record<string, string> = {}
|
|
854
|
+
const nextPath = [...path, field.name, index];
|
|
855
|
+
const metadataFields: Record<string, string> = {};
|
|
775
856
|
templateFields.forEach((field) => {
|
|
776
|
-
metadataFields[field.name] = [...nextPath, field.name].join('.')
|
|
777
|
-
})
|
|
857
|
+
metadataFields[field.name] = [...nextPath, field.name].join('.');
|
|
858
|
+
});
|
|
778
859
|
return {
|
|
779
860
|
__typename: NAMER.dataTypeName(field.namespace),
|
|
780
861
|
_tina_metadata: {
|
|
@@ -790,15 +871,15 @@ const resolveFieldValue = ({
|
|
|
790
871
|
id,
|
|
791
872
|
pathToDocument,
|
|
792
873
|
}),
|
|
793
|
-
}
|
|
794
|
-
})
|
|
874
|
+
};
|
|
875
|
+
});
|
|
795
876
|
}
|
|
796
877
|
} else {
|
|
797
|
-
const nextPath = [...path, field.name]
|
|
798
|
-
const metadataFields: Record<string, string> = {}
|
|
878
|
+
const nextPath = [...path, field.name];
|
|
879
|
+
const metadataFields: Record<string, string> = {};
|
|
799
880
|
templateFields.forEach((field) => {
|
|
800
|
-
metadataFields[field.name] = [...nextPath, field.name].join('.')
|
|
801
|
-
})
|
|
881
|
+
metadataFields[field.name] = [...nextPath, field.name].join('.');
|
|
882
|
+
});
|
|
802
883
|
return {
|
|
803
884
|
__typename: NAMER.dataTypeName(field.namespace),
|
|
804
885
|
_tina_metadata: {
|
|
@@ -814,18 +895,21 @@ const resolveFieldValue = ({
|
|
|
814
895
|
id,
|
|
815
896
|
pathToDocument,
|
|
816
897
|
}),
|
|
817
|
-
}
|
|
898
|
+
};
|
|
818
899
|
}
|
|
819
900
|
}
|
|
820
901
|
default: {
|
|
821
|
-
return value
|
|
902
|
+
return value;
|
|
822
903
|
}
|
|
823
904
|
}
|
|
824
|
-
}
|
|
905
|
+
};
|
|
825
906
|
|
|
826
907
|
const getDocument = async (id: string, tina: Client) => {
|
|
827
908
|
const response = await tina.request<{
|
|
828
|
-
node: {
|
|
909
|
+
node: {
|
|
910
|
+
_internalSys: SystemInfo;
|
|
911
|
+
_internalValues: Record<string, unknown>;
|
|
912
|
+
};
|
|
829
913
|
}>(
|
|
830
914
|
`query GetNode($id: String!) {
|
|
831
915
|
node(id: $id) {
|
|
@@ -858,29 +942,29 @@ _internalSys: _sys {
|
|
|
858
942
|
}
|
|
859
943
|
}`,
|
|
860
944
|
{ variables: { id: id } }
|
|
861
|
-
)
|
|
862
|
-
return response.node
|
|
863
|
-
}
|
|
945
|
+
);
|
|
946
|
+
return response.node;
|
|
947
|
+
};
|
|
864
948
|
|
|
865
949
|
const expandPayload = async (
|
|
866
950
|
payload: Payload,
|
|
867
951
|
cms: TinaCMS
|
|
868
952
|
): Promise<Payload> => {
|
|
869
|
-
const { query, variables } = payload
|
|
870
|
-
const documentNode = G.parse(query)
|
|
871
|
-
const expandedDocumentNode = expandQuery({ schema, documentNode })
|
|
872
|
-
const expandedQuery = G.print(expandedDocumentNode)
|
|
953
|
+
const { query, variables } = payload;
|
|
954
|
+
const documentNode = G.parse(query);
|
|
955
|
+
const expandedDocumentNode = expandQuery({ schema, documentNode });
|
|
956
|
+
const expandedQuery = G.print(expandedDocumentNode);
|
|
873
957
|
const expandedData = await cms.api.tina.request<object>(expandedQuery, {
|
|
874
958
|
variables,
|
|
875
|
-
})
|
|
959
|
+
});
|
|
876
960
|
|
|
877
961
|
const expandedDocumentNodeForResolver = expandQuery({
|
|
878
962
|
schema: schemaForResolver,
|
|
879
963
|
documentNode,
|
|
880
|
-
})
|
|
881
|
-
const expandedQueryForResolver = G.print(expandedDocumentNodeForResolver)
|
|
882
|
-
return { ...payload, expandedQuery, expandedData, expandedQueryForResolver }
|
|
883
|
-
}
|
|
964
|
+
});
|
|
965
|
+
const expandedQueryForResolver = G.print(expandedDocumentNodeForResolver);
|
|
966
|
+
return { ...payload, expandedQuery, expandedData, expandedQueryForResolver };
|
|
967
|
+
};
|
|
884
968
|
|
|
885
969
|
/**
|
|
886
970
|
* When we resolve the graphql data we check for these errors,
|
|
@@ -888,11 +972,11 @@ const expandPayload = async (
|
|
|
888
972
|
* process it once we have that document
|
|
889
973
|
*/
|
|
890
974
|
class NoFormError extends Error {
|
|
891
|
-
id: string
|
|
975
|
+
id: string;
|
|
892
976
|
constructor(msg: string, id: string) {
|
|
893
|
-
super(msg)
|
|
894
|
-
this.id = id
|
|
895
|
-
Object.setPrototypeOf(this, NoFormError.prototype)
|
|
977
|
+
super(msg);
|
|
978
|
+
this.id = id;
|
|
979
|
+
Object.setPrototypeOf(this, NoFormError.prototype);
|
|
896
980
|
}
|
|
897
981
|
}
|
|
898
982
|
|
|
@@ -900,22 +984,22 @@ const getTemplateForDocument = (
|
|
|
900
984
|
resolvedDocument: ResolvedDocument,
|
|
901
985
|
tinaSchema: TinaSchema
|
|
902
986
|
) => {
|
|
903
|
-
const id = resolvedDocument._internalSys.path
|
|
904
|
-
let collection: Collection<true> | undefined
|
|
987
|
+
const id = resolvedDocument._internalSys.path;
|
|
988
|
+
let collection: Collection<true> | undefined;
|
|
905
989
|
try {
|
|
906
|
-
collection = tinaSchema.getCollectionByFullPath(id)
|
|
990
|
+
collection = tinaSchema.getCollectionByFullPath(id);
|
|
907
991
|
} catch (e) {}
|
|
908
992
|
|
|
909
993
|
if (!collection) {
|
|
910
|
-
throw new Error(`Unable to determine collection for path ${id}`)
|
|
994
|
+
throw new Error(`Unable to determine collection for path ${id}`);
|
|
911
995
|
}
|
|
912
996
|
|
|
913
997
|
const template = tinaSchema.getTemplateForData({
|
|
914
998
|
data: resolvedDocument._internalValues,
|
|
915
999
|
collection,
|
|
916
|
-
})
|
|
917
|
-
return { template, collection }
|
|
918
|
-
}
|
|
1000
|
+
});
|
|
1001
|
+
return { template, collection };
|
|
1002
|
+
};
|
|
919
1003
|
|
|
920
1004
|
const buildForm = ({
|
|
921
1005
|
resolvedDocument,
|
|
@@ -923,18 +1007,18 @@ const buildForm = ({
|
|
|
923
1007
|
payloadId,
|
|
924
1008
|
cms,
|
|
925
1009
|
}: {
|
|
926
|
-
resolvedDocument: ResolvedDocument
|
|
927
|
-
tinaSchema: TinaSchema
|
|
928
|
-
payloadId: string
|
|
929
|
-
cms: TinaCMS
|
|
1010
|
+
resolvedDocument: ResolvedDocument;
|
|
1011
|
+
tinaSchema: TinaSchema;
|
|
1012
|
+
payloadId: string;
|
|
1013
|
+
cms: TinaCMS;
|
|
930
1014
|
}) => {
|
|
931
1015
|
const { template, collection } = getTemplateForDocument(
|
|
932
1016
|
resolvedDocument,
|
|
933
1017
|
tinaSchema
|
|
934
|
-
)
|
|
935
|
-
const id = resolvedDocument._internalSys.path
|
|
936
|
-
let form: Form | undefined
|
|
937
|
-
let shouldRegisterForm = true
|
|
1018
|
+
);
|
|
1019
|
+
const id = resolvedDocument._internalSys.path;
|
|
1020
|
+
let form: Form | undefined;
|
|
1021
|
+
let shouldRegisterForm = true;
|
|
938
1022
|
const formConfig: FormOptions<any> = {
|
|
939
1023
|
id,
|
|
940
1024
|
initialValues: resolvedDocument._internalValues,
|
|
@@ -947,10 +1031,10 @@ const buildForm = ({
|
|
|
947
1031
|
cms
|
|
948
1032
|
),
|
|
949
1033
|
label: collection.label || collection.name,
|
|
950
|
-
}
|
|
1034
|
+
};
|
|
951
1035
|
if (tinaSchema.config.config?.formifyCallback) {
|
|
952
1036
|
const callback = tinaSchema.config.config
|
|
953
|
-
?.formifyCallback as FormifyCallback
|
|
1037
|
+
?.formifyCallback as FormifyCallback;
|
|
954
1038
|
form =
|
|
955
1039
|
callback(
|
|
956
1040
|
{
|
|
@@ -960,30 +1044,30 @@ const buildForm = ({
|
|
|
960
1044
|
formConfig,
|
|
961
1045
|
},
|
|
962
1046
|
cms
|
|
963
|
-
) || undefined
|
|
1047
|
+
) || undefined;
|
|
964
1048
|
if (!form) {
|
|
965
1049
|
// If the form isn't created from formify, we still
|
|
966
1050
|
// need it, just don't show it to the user.
|
|
967
|
-
shouldRegisterForm = false
|
|
968
|
-
form = new Form(formConfig)
|
|
1051
|
+
shouldRegisterForm = false;
|
|
1052
|
+
form = new Form(formConfig);
|
|
969
1053
|
}
|
|
970
1054
|
} else {
|
|
971
1055
|
if (collection.ui?.global) {
|
|
972
|
-
form = createGlobalForm(formConfig)
|
|
1056
|
+
form = createGlobalForm(formConfig);
|
|
973
1057
|
} else {
|
|
974
|
-
form = createForm(formConfig)
|
|
1058
|
+
form = createForm(formConfig);
|
|
975
1059
|
}
|
|
976
1060
|
}
|
|
977
1061
|
if (form) {
|
|
978
1062
|
if (shouldRegisterForm) {
|
|
979
1063
|
if (collection.ui?.global) {
|
|
980
|
-
cms.plugins.add(new GlobalFormPlugin(form))
|
|
1064
|
+
cms.plugins.add(new GlobalFormPlugin(form));
|
|
981
1065
|
}
|
|
982
|
-
cms.dispatch({ type: 'forms:add', value: form })
|
|
1066
|
+
cms.dispatch({ type: 'forms:add', value: form });
|
|
983
1067
|
}
|
|
984
1068
|
}
|
|
985
1069
|
if (!form) {
|
|
986
|
-
throw new Error(`No form registered for ${id}.`)
|
|
1070
|
+
throw new Error(`No form registered for ${id}.`);
|
|
987
1071
|
}
|
|
988
|
-
return { template, form }
|
|
989
|
-
}
|
|
1072
|
+
return { template, form };
|
|
1073
|
+
};
|