@tinacms/app 0.0.26 → 0.0.27
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/appFiles/src/App.tsx +2 -1
- package/appFiles/src/fields/rich-text/monaco/mdx.js +46 -0
- package/appFiles/src/lib/formify/index.ts +20 -0
- package/appFiles/src/lib/machines/document-machine.ts +23 -18
- package/appFiles/src/lib/machines/query-machine.ts +199 -249
- package/appFiles/src/preview.tsx +2 -0
- package/dist/test-utils.js +20 -0
- package/package.json +3 -3
package/appFiles/src/App.tsx
CHANGED
|
@@ -50,9 +50,10 @@ const SetPreview = ({ outputFolder }: { outputFolder: string }) => {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export const TinaAdminWrapper = () => {
|
|
53
|
+
const schema = { ...config?.schema, config }
|
|
53
54
|
return (
|
|
54
55
|
// @ts-ignore JSX element type 'TinaCMS' does not have any construct or call signatures.ts(2604)
|
|
55
|
-
<TinaCMS {...config} client={{ apiUrl: __API_URL__ }}>
|
|
56
|
+
<TinaCMS {...config} schema={schema} client={{ apiUrl: __API_URL__ }}>
|
|
56
57
|
<SetPreview outputFolder={config.build.outputFolder} />
|
|
57
58
|
<TinaAdmin preview={Preview} config={config} />
|
|
58
59
|
</TinaCMS>
|
|
@@ -30111,6 +30111,49 @@ function remarkMdx(options = {}) {
|
|
|
30111
30111
|
}
|
|
30112
30112
|
}
|
|
30113
30113
|
|
|
30114
|
+
// ../../../node_modules/.pnpm/hast-util-whitespace@2.0.0/node_modules/hast-util-whitespace/index.js
|
|
30115
|
+
function whitespace(thing) {
|
|
30116
|
+
var value = thing && typeof thing === "object" && thing.type === "text" ? thing.value || "" : thing;
|
|
30117
|
+
return typeof value === "string" && value.replace(/[ \t\n\f\r]/g, "") === "";
|
|
30118
|
+
}
|
|
30119
|
+
|
|
30120
|
+
// ../../../node_modules/.pnpm/remark-unwrap-images@3.0.1/node_modules/remark-unwrap-images/index.js
|
|
30121
|
+
var unknown2 = 1;
|
|
30122
|
+
var containsImage = 2;
|
|
30123
|
+
var containsOther = 3;
|
|
30124
|
+
function remarkUnwrapImages() {
|
|
30125
|
+
return (tree) => {
|
|
30126
|
+
visit(tree, "paragraph", (node, index2, parent) => {
|
|
30127
|
+
if (parent && typeof index2 === "number" && applicable(node) === containsImage) {
|
|
30128
|
+
parent.children.splice(index2, 1, ...node.children);
|
|
30129
|
+
return [SKIP, index2];
|
|
30130
|
+
}
|
|
30131
|
+
});
|
|
30132
|
+
};
|
|
30133
|
+
}
|
|
30134
|
+
function applicable(node, inLink) {
|
|
30135
|
+
let image2 = unknown2;
|
|
30136
|
+
let index2 = -1;
|
|
30137
|
+
while (++index2 < node.children.length) {
|
|
30138
|
+
const child = node.children[index2];
|
|
30139
|
+
if (whitespace(child)) {
|
|
30140
|
+
} else if (child.type === "image" || child.type === "imageReference") {
|
|
30141
|
+
image2 = containsImage;
|
|
30142
|
+
} else if (!inLink && (child.type === "link" || child.type === "linkReference")) {
|
|
30143
|
+
const linkResult = applicable(child, true);
|
|
30144
|
+
if (linkResult === containsOther) {
|
|
30145
|
+
return containsOther;
|
|
30146
|
+
}
|
|
30147
|
+
if (linkResult === containsImage) {
|
|
30148
|
+
image2 = containsImage;
|
|
30149
|
+
}
|
|
30150
|
+
} else {
|
|
30151
|
+
return containsOther;
|
|
30152
|
+
}
|
|
30153
|
+
}
|
|
30154
|
+
return image2;
|
|
30155
|
+
}
|
|
30156
|
+
|
|
30114
30157
|
// ../../../node_modules/.pnpm/lodash-es@4.17.21/node_modules/lodash-es/_freeGlobal.js
|
|
30115
30158
|
var freeGlobal = typeof global == "object" && global && global.Object === Object && global;
|
|
30116
30159
|
var freeGlobal_default = freeGlobal;
|
|
@@ -30510,6 +30553,8 @@ var remarkToSlate = (root3, field, imageCallback) => {
|
|
|
30510
30553
|
return code2(content4);
|
|
30511
30554
|
case "paragraph":
|
|
30512
30555
|
return paragraph2(content4);
|
|
30556
|
+
case "image":
|
|
30557
|
+
return image2(content4);
|
|
30513
30558
|
case "mdxJsxFlowElement":
|
|
30514
30559
|
return mdxJsxElement(content4, field, imageCallback);
|
|
30515
30560
|
case "thematicBreak":
|
|
@@ -30816,6 +30861,7 @@ var markdownToAst = (value, field) => {
|
|
|
30816
30861
|
if (!tree) {
|
|
30817
30862
|
throw new Error("Error parsing markdown");
|
|
30818
30863
|
}
|
|
30864
|
+
remarkUnwrapImages({})(tree);
|
|
30819
30865
|
return tree;
|
|
30820
30866
|
} catch (e) {
|
|
30821
30867
|
throw new RichTextParseError(e, e.position);
|
|
@@ -304,8 +304,28 @@ export const formify = async ({
|
|
|
304
304
|
const node = G.parse(`
|
|
305
305
|
query Sample {
|
|
306
306
|
...on Document {
|
|
307
|
+
_internalValues: _values
|
|
307
308
|
_internalSys: _sys {
|
|
309
|
+
breadcrumbs
|
|
310
|
+
basename
|
|
311
|
+
filename
|
|
308
312
|
path
|
|
313
|
+
extension
|
|
314
|
+
relativePath
|
|
315
|
+
title
|
|
316
|
+
template
|
|
317
|
+
collection {
|
|
318
|
+
name
|
|
319
|
+
slug
|
|
320
|
+
label
|
|
321
|
+
path
|
|
322
|
+
format
|
|
323
|
+
matches
|
|
324
|
+
templates
|
|
325
|
+
fields
|
|
326
|
+
__typename
|
|
327
|
+
}
|
|
328
|
+
__typename
|
|
309
329
|
}
|
|
310
330
|
}
|
|
311
331
|
}`)
|
|
@@ -25,7 +25,7 @@ export type FormType = Form<FormValues, FieldType>
|
|
|
25
25
|
|
|
26
26
|
export type DataType = Record<string, unknown>
|
|
27
27
|
|
|
28
|
-
type Data = {
|
|
28
|
+
export type Data = {
|
|
29
29
|
_internalValues: object
|
|
30
30
|
_internalSys: {
|
|
31
31
|
breadcrumbs: string[]
|
|
@@ -136,10 +136,14 @@ export const documentMachine =
|
|
|
136
136
|
services: {
|
|
137
137
|
initializer: async (context) => {
|
|
138
138
|
const tina = context.cms.api.tina as Client
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
let node: Data
|
|
140
|
+
if (context.data) {
|
|
141
|
+
node = context.data
|
|
142
|
+
} else {
|
|
143
|
+
const response = await tina.request<{
|
|
144
|
+
node: Data
|
|
145
|
+
}>(
|
|
146
|
+
`query GetNode($id: String!) {
|
|
143
147
|
node(id: $id) {
|
|
144
148
|
...on Document {
|
|
145
149
|
_internalValues: _values
|
|
@@ -168,14 +172,16 @@ export const documentMachine =
|
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
174
|
}`,
|
|
171
|
-
|
|
172
|
-
|
|
175
|
+
{ variables: { id: context.id } }
|
|
176
|
+
)
|
|
177
|
+
node = response.node
|
|
178
|
+
}
|
|
173
179
|
const schema = context.cms.api.tina.schema as TinaSchema
|
|
174
180
|
if (!schema) {
|
|
175
181
|
throw new Error(`Schema must be provided`)
|
|
176
182
|
}
|
|
177
183
|
const collection = schema.getCollection(
|
|
178
|
-
|
|
184
|
+
node._internalSys.collection.name
|
|
179
185
|
)
|
|
180
186
|
let template: Templateable
|
|
181
187
|
if (collection.templates) {
|
|
@@ -183,19 +189,19 @@ export const documentMachine =
|
|
|
183
189
|
if (typeof template === 'string') {
|
|
184
190
|
throw new Error(`Global templates not supported`)
|
|
185
191
|
}
|
|
186
|
-
return template.name ===
|
|
192
|
+
return template.name === node._internalSys.template
|
|
187
193
|
}) as Templateable
|
|
188
194
|
} else {
|
|
189
195
|
template = collection
|
|
190
196
|
}
|
|
191
197
|
if (!template) {
|
|
192
198
|
throw new Error(
|
|
193
|
-
`Unable to find template for node ${
|
|
199
|
+
`Unable to find template for node ${node._internalSys.path}`
|
|
194
200
|
)
|
|
195
201
|
}
|
|
196
202
|
const resolvedForm = resolveForm({
|
|
197
203
|
collection,
|
|
198
|
-
basename:
|
|
204
|
+
basename: node._internalSys.filename,
|
|
199
205
|
schema,
|
|
200
206
|
template,
|
|
201
207
|
})
|
|
@@ -211,10 +217,10 @@ export const documentMachine =
|
|
|
211
217
|
|
|
212
218
|
await context.cms.api.tina.request(mutationString, {
|
|
213
219
|
variables: {
|
|
214
|
-
collection:
|
|
215
|
-
relativePath:
|
|
220
|
+
collection: node._internalSys.collection.name,
|
|
221
|
+
relativePath: node._internalSys.relativePath,
|
|
216
222
|
params: schema.transformPayload(
|
|
217
|
-
|
|
223
|
+
node._internalSys.collection.name,
|
|
218
224
|
payload
|
|
219
225
|
),
|
|
220
226
|
},
|
|
@@ -230,9 +236,8 @@ export const documentMachine =
|
|
|
230
236
|
const formConfig = {
|
|
231
237
|
id: context.id,
|
|
232
238
|
label:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
initialValues: response.node._internalValues,
|
|
239
|
+
node._internalSys.title || node._internalSys.collection.label,
|
|
240
|
+
initialValues: node._internalValues,
|
|
236
241
|
fields: resolvedForm.fields,
|
|
237
242
|
onSubmit,
|
|
238
243
|
}
|
|
@@ -250,7 +255,7 @@ export const documentMachine =
|
|
|
250
255
|
true,
|
|
251
256
|
onSubmit
|
|
252
257
|
)
|
|
253
|
-
return { form, data:
|
|
258
|
+
return { form, data: node }
|
|
254
259
|
},
|
|
255
260
|
},
|
|
256
261
|
}
|
|
@@ -10,12 +10,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
10
10
|
See the License for the specific language governing permissions and
|
|
11
11
|
limitations under the License.
|
|
12
12
|
*/
|
|
13
|
-
import { assign,
|
|
13
|
+
import { assign, createMachine, spawn } from 'xstate'
|
|
14
14
|
import {
|
|
15
15
|
Form,
|
|
16
16
|
TinaCMS,
|
|
17
17
|
NAMER,
|
|
18
|
-
Template,
|
|
19
18
|
TinaFieldEnriched,
|
|
20
19
|
TinaCollection,
|
|
21
20
|
TinaSchema,
|
|
@@ -24,9 +23,8 @@ import {
|
|
|
24
23
|
} from 'tinacms'
|
|
25
24
|
import * as G from 'graphql'
|
|
26
25
|
import { formify } from '../formify'
|
|
27
|
-
import {
|
|
26
|
+
import { Data, documentMachine } from './document-machine'
|
|
28
27
|
import type { ActorRefFrom } from 'xstate'
|
|
29
|
-
import { Blueprint2 } from '../formify'
|
|
30
28
|
|
|
31
29
|
export type DataType = Record<string, unknown>
|
|
32
30
|
type DocumentInfo = {
|
|
@@ -43,18 +41,21 @@ type ContextType = {
|
|
|
43
41
|
id: null | string
|
|
44
42
|
data: null | DataType
|
|
45
43
|
cms: TinaCMS
|
|
46
|
-
|
|
44
|
+
documentNode: G.DocumentNode
|
|
45
|
+
variables: object
|
|
47
46
|
iframe: null | HTMLIFrameElement
|
|
47
|
+
registerSubForms?: boolean
|
|
48
48
|
formifyCallback: (args: any) => Form
|
|
49
49
|
documentMap: DocumentMap
|
|
50
|
-
|
|
50
|
+
documents: Data[]
|
|
51
51
|
}
|
|
52
52
|
export const initialContext: Omit<ContextType, 'cms' | 'formifyCallback'> = {
|
|
53
53
|
id: null,
|
|
54
54
|
data: null,
|
|
55
|
-
|
|
56
|
-
blueprints: [],
|
|
55
|
+
variables: {},
|
|
57
56
|
documentMap: {},
|
|
57
|
+
documents: [],
|
|
58
|
+
documentNode: { kind: 'Document', definitions: [] },
|
|
58
59
|
iframe: null,
|
|
59
60
|
}
|
|
60
61
|
export const queryMachine =
|
|
@@ -68,7 +69,6 @@ export const queryMachine =
|
|
|
68
69
|
initializer: {
|
|
69
70
|
data: {
|
|
70
71
|
data: DataType
|
|
71
|
-
blueprints: Blueprint2[]
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
setter: {
|
|
@@ -197,9 +197,6 @@ export const queryMachine =
|
|
|
197
197
|
REMOVE_QUERY: {
|
|
198
198
|
target: 'idle',
|
|
199
199
|
},
|
|
200
|
-
SELECT_DOCUMENT: {
|
|
201
|
-
actions: 'selectDocument',
|
|
202
|
-
},
|
|
203
200
|
FIELD_CHANGE: {
|
|
204
201
|
target: 'pending',
|
|
205
202
|
},
|
|
@@ -214,10 +211,6 @@ export const queryMachine =
|
|
|
214
211
|
actions: {
|
|
215
212
|
handleError: (_context, event) => console.error(event.data),
|
|
216
213
|
handleMissingDocument: assign((context, event) => {
|
|
217
|
-
count = count + 1
|
|
218
|
-
if (count > 50) {
|
|
219
|
-
throw new Error('infinite loop')
|
|
220
|
-
}
|
|
221
214
|
if (event.data instanceof QueryError) {
|
|
222
215
|
if (context.documentMap[event.data.id]) {
|
|
223
216
|
// Already exists
|
|
@@ -226,6 +219,9 @@ export const queryMachine =
|
|
|
226
219
|
if (!event.data.id) {
|
|
227
220
|
return context
|
|
228
221
|
}
|
|
222
|
+
const existingData = context.documents.find(
|
|
223
|
+
(doc) => doc._internalSys.path === event.data.id
|
|
224
|
+
)
|
|
229
225
|
const doc = {
|
|
230
226
|
ref: spawn(
|
|
231
227
|
documentMachine.withContext({
|
|
@@ -233,7 +229,7 @@ export const queryMachine =
|
|
|
233
229
|
cms: context.cms,
|
|
234
230
|
formifyCallback: context.formifyCallback,
|
|
235
231
|
form: null,
|
|
236
|
-
data: null,
|
|
232
|
+
data: existingData || null,
|
|
237
233
|
})
|
|
238
234
|
),
|
|
239
235
|
}
|
|
@@ -271,12 +267,6 @@ export const queryMachine =
|
|
|
271
267
|
...event.data,
|
|
272
268
|
}
|
|
273
269
|
}),
|
|
274
|
-
selectDocument: assign((context, event) => {
|
|
275
|
-
return {
|
|
276
|
-
...context,
|
|
277
|
-
selectedDocument: event.value,
|
|
278
|
-
}
|
|
279
|
-
}),
|
|
280
270
|
setIframe: assign((context, event) => {
|
|
281
271
|
return {
|
|
282
272
|
...context,
|
|
@@ -299,41 +289,110 @@ export const queryMachine =
|
|
|
299
289
|
},
|
|
300
290
|
services: {
|
|
301
291
|
setter: async (context) => {
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
292
|
+
const tinaSchema = context.cms.api.tina.schema as TinaSchema
|
|
293
|
+
const gqlSchema = context.cms.api.tina.gqlSchema
|
|
294
|
+
const missingForms: { id: string; skipFormRegister: boolean }[] = []
|
|
295
|
+
const newData = await G.graphql({
|
|
296
|
+
schema: gqlSchema,
|
|
297
|
+
source: G.print(context.documentNode),
|
|
298
|
+
rootValue: context.data,
|
|
299
|
+
variableValues: context.variables,
|
|
300
|
+
fieldResolver: (source, args, _context, info) => {
|
|
301
|
+
const fieldName = info.fieldName
|
|
302
|
+
/**
|
|
303
|
+
* Formify adds `_internalSys` and `_internalValues` to the query
|
|
304
|
+
* and a user's query might also include `_values` or `_sys`, but
|
|
305
|
+
* it may not contain all of the info we need, so the actual
|
|
306
|
+
* source of truth for these values is our alias ones, which are
|
|
307
|
+
* also guaranteed to include all of the values another `_sys` query
|
|
308
|
+
* might include
|
|
309
|
+
*/
|
|
310
|
+
if (fieldName === '_sys') {
|
|
311
|
+
return source._internalSys
|
|
312
|
+
}
|
|
313
|
+
if (fieldName === '_values') {
|
|
314
|
+
return source._internalValues
|
|
315
|
+
}
|
|
316
|
+
if (isNodeType(info.returnType)) {
|
|
317
|
+
const existingValue = source[fieldName]
|
|
318
|
+
let skipFormRegister = false
|
|
319
|
+
if (!existingValue) {
|
|
320
|
+
return null
|
|
321
|
+
}
|
|
322
|
+
let path: string = ''
|
|
323
|
+
if (typeof existingValue === 'string') {
|
|
324
|
+
// this is a reference value (eg. post.author)
|
|
325
|
+
skipFormRegister = true
|
|
326
|
+
path = existingValue
|
|
327
|
+
} else {
|
|
328
|
+
path = existingValue._internalSys.path
|
|
329
|
+
}
|
|
330
|
+
if (context.documentMap[path]) {
|
|
331
|
+
const documentMachine = context.documentMap[path].ref
|
|
332
|
+
const documentContext = documentMachine.getSnapshot()?.context
|
|
333
|
+
if (!documentContext) {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`Document not set up properly for id: ${path}`
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
const { data, form } = documentContext
|
|
339
|
+
const values = form?.values
|
|
340
|
+
if (!data || !form || !values) {
|
|
341
|
+
throw new Error(
|
|
342
|
+
`Document not set up properly for id: ${path}`
|
|
343
|
+
)
|
|
344
|
+
}
|
|
345
|
+
const collectionName = data._internalSys.collection.name
|
|
346
|
+
const extraValues = documentContext.data
|
|
347
|
+
const formVal = resolveFormValue({
|
|
348
|
+
fields: form.fields,
|
|
349
|
+
values: values,
|
|
350
|
+
tinaSchema,
|
|
351
|
+
})
|
|
352
|
+
const template = tinaSchema.getTemplateForData({
|
|
353
|
+
data: form.values,
|
|
354
|
+
collection: tinaSchema.getCollection(collectionName),
|
|
355
|
+
})
|
|
356
|
+
return {
|
|
357
|
+
...extraValues,
|
|
358
|
+
...formVal,
|
|
359
|
+
_sys: data._internalSys,
|
|
360
|
+
id: path,
|
|
361
|
+
__typename: NAMER.dataTypeName(template.namespace),
|
|
362
|
+
}
|
|
316
363
|
} else {
|
|
317
|
-
|
|
364
|
+
// TODO: when we support forms in lists, remove this check
|
|
365
|
+
// This checks that we're at least 2 levels deep, meaning top-level
|
|
366
|
+
// queries list page(relativePath: '...') will be registered, but
|
|
367
|
+
// not connection nodes like pageConnection.edges.node
|
|
368
|
+
if (info.path?.prev?.prev) {
|
|
369
|
+
skipFormRegister = true
|
|
370
|
+
}
|
|
371
|
+
missingForms.push({ id: path, skipFormRegister })
|
|
372
|
+
return null
|
|
318
373
|
}
|
|
319
374
|
}
|
|
320
|
-
|
|
321
|
-
|
|
375
|
+
return source[fieldName]
|
|
376
|
+
},
|
|
377
|
+
})
|
|
378
|
+
if (missingForms.length > 0) {
|
|
379
|
+
// Only run this one at a time
|
|
380
|
+
const missingForm = missingForms[0]
|
|
381
|
+
throw new QueryError(
|
|
382
|
+
`Unable to resolve form for initial document`,
|
|
383
|
+
missingForm.id,
|
|
384
|
+
missingForm.skipFormRegister
|
|
385
|
+
)
|
|
322
386
|
}
|
|
323
|
-
|
|
324
|
-
return { data: accum }
|
|
387
|
+
return { data: newData.data }
|
|
325
388
|
},
|
|
326
389
|
initializer: async (context, event) => {
|
|
327
390
|
const tina = context.cms.api.tina as Client
|
|
328
391
|
const schema = await tina.getSchema()
|
|
329
392
|
const documentNode = G.parse(event.value.query)
|
|
330
|
-
const
|
|
331
|
-
if (!optimizedQuery) {
|
|
332
|
-
throw new Error(`Unable to optimize query`)
|
|
333
|
-
}
|
|
334
|
-
const { blueprints, formifiedQuery } = await formify({
|
|
393
|
+
const { formifiedQuery } = await formify({
|
|
335
394
|
schema,
|
|
336
|
-
optimizedDocumentNode:
|
|
395
|
+
optimizedDocumentNode: documentNode,
|
|
337
396
|
})
|
|
338
397
|
const data = (await context.cms.api.tina.request(
|
|
339
398
|
G.print(formifiedQuery),
|
|
@@ -341,17 +400,29 @@ export const queryMachine =
|
|
|
341
400
|
variables: event.value.variables,
|
|
342
401
|
}
|
|
343
402
|
)) as DataType
|
|
403
|
+
const documents: Data[] = []
|
|
404
|
+
// step through every value in the payload to find the documents
|
|
405
|
+
JSON.stringify(data, (key, value) => {
|
|
406
|
+
if (value?._internalValues) {
|
|
407
|
+
documents.push(value)
|
|
408
|
+
}
|
|
409
|
+
return value
|
|
410
|
+
})
|
|
344
411
|
return {
|
|
345
412
|
data,
|
|
346
|
-
|
|
413
|
+
documents,
|
|
414
|
+
variables: event.value.variables,
|
|
415
|
+
documentNode: formifiedQuery,
|
|
347
416
|
id: event.value.id,
|
|
348
417
|
}
|
|
349
418
|
},
|
|
350
419
|
onChangeCallback: (context) => (callback, _onReceive) => {
|
|
351
420
|
const schema = context.cms.api.tina.schema as TinaSchema
|
|
352
421
|
Object.values(context.documentMap).forEach((documentMachine) => {
|
|
353
|
-
if (
|
|
354
|
-
|
|
422
|
+
if (!context.registerSubForms) {
|
|
423
|
+
if (documentMachine.skipFormRegister) {
|
|
424
|
+
return
|
|
425
|
+
}
|
|
355
426
|
}
|
|
356
427
|
const documentContext = documentMachine.ref.getSnapshot()?.context
|
|
357
428
|
const collectionName =
|
|
@@ -397,242 +468,121 @@ class QueryError extends Error {
|
|
|
397
468
|
this.skipFormRegister = skipFormRegister
|
|
398
469
|
}
|
|
399
470
|
}
|
|
400
|
-
let count = 0
|
|
401
|
-
|
|
402
|
-
// https://github.com/oleics/node-is-scalar/blob/master/index.js
|
|
403
|
-
const withSymbol = typeof Symbol !== 'undefined'
|
|
404
|
-
function isScalar(value: unknown) {
|
|
405
|
-
const type = typeof value
|
|
406
|
-
if (type === 'string') return true
|
|
407
|
-
if (type === 'number') return true
|
|
408
|
-
if (type === 'boolean') return true
|
|
409
|
-
if (withSymbol === true && type === 'symbol') return true
|
|
410
471
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
return false
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
const setData = (
|
|
421
|
-
data: { [key: string]: unknown },
|
|
422
|
-
blueprint: Blueprint2,
|
|
423
|
-
context: ContextFrom<typeof queryMachine>
|
|
424
|
-
) => {
|
|
425
|
-
if (data?._internalSys) {
|
|
426
|
-
const id = data._internalSys?.path
|
|
427
|
-
const doc = context.documentMap[id]
|
|
428
|
-
const docContext = doc?.ref?.getSnapshot()?.context
|
|
429
|
-
const form = docContext?.form
|
|
430
|
-
if (!form) {
|
|
431
|
-
const skipFormRegiester = (blueprint.path?.length || 0) > 2
|
|
432
|
-
throw new QueryError(
|
|
433
|
-
`Unable to resolve form for initial document`,
|
|
434
|
-
id,
|
|
435
|
-
skipFormRegiester
|
|
436
|
-
)
|
|
472
|
+
const isNodeType = (type: G.GraphQLOutputType) => {
|
|
473
|
+
const namedType = G.getNamedType(type)
|
|
474
|
+
if (G.isInterfaceType(namedType)) {
|
|
475
|
+
if (namedType.name === 'Node') {
|
|
476
|
+
return true
|
|
437
477
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
478
|
+
}
|
|
479
|
+
if (G.isUnionType(namedType)) {
|
|
480
|
+
const types = namedType.getTypes()
|
|
481
|
+
if (
|
|
482
|
+
types.every((type) => {
|
|
483
|
+
return type.getInterfaces().some((intfc) => intfc.name === 'Node')
|
|
484
|
+
})
|
|
485
|
+
) {
|
|
486
|
+
return true
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (G.isObjectType(namedType)) {
|
|
490
|
+
if (namedType.getInterfaces().some((intfc) => intfc.name === 'Node')) {
|
|
491
|
+
return true
|
|
441
492
|
}
|
|
442
|
-
|
|
443
|
-
const fields = form.fields
|
|
444
|
-
const result = resolveForm({
|
|
445
|
-
id,
|
|
446
|
-
fields,
|
|
447
|
-
sys: _internalSys,
|
|
448
|
-
values: form.values,
|
|
449
|
-
fieldsToInclude: blueprint.fields,
|
|
450
|
-
context,
|
|
451
|
-
})
|
|
452
|
-
return { ...docContext.data, ...result }
|
|
453
|
-
} else {
|
|
454
|
-
// this isn't a node
|
|
455
493
|
}
|
|
456
|
-
return data
|
|
457
494
|
}
|
|
458
495
|
|
|
459
|
-
const
|
|
460
|
-
id,
|
|
496
|
+
const resolveFormValue = <T extends Record<string, unknown>>({
|
|
461
497
|
fields,
|
|
462
|
-
sys,
|
|
463
498
|
values,
|
|
464
|
-
|
|
465
|
-
context,
|
|
499
|
+
tinaSchema,
|
|
466
500
|
}: {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
fieldsToInclude: Blueprint2['fields']
|
|
472
|
-
context: ContextFrom<typeof queryMachine>
|
|
473
|
-
}) => {
|
|
501
|
+
fields: TinaFieldEnriched[]
|
|
502
|
+
values: T
|
|
503
|
+
tinaSchema: TinaSchema
|
|
504
|
+
}): T & { __typename?: string } => {
|
|
474
505
|
const accum: Record<string, unknown> = {}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
fieldsToInclude?.forEach((fieldToInclude) => {
|
|
480
|
-
const field = fields.find((field) => fieldToInclude.name === field.name)
|
|
481
|
-
if (!field) {
|
|
482
|
-
if (fieldToInclude.name === 'id') {
|
|
483
|
-
accum[fieldToInclude.alias] = id
|
|
484
|
-
} else if (fieldToInclude.name === '_sys') {
|
|
485
|
-
if (fieldToInclude.alias !== '_internalSys') {
|
|
486
|
-
const sysAccum: Record<string, unknown> = {}
|
|
487
|
-
// TODO: loop through these and actually use their alias values
|
|
488
|
-
fieldToInclude.fields?.forEach((field) => {
|
|
489
|
-
sysAccum[field.alias] = sys[field.name]
|
|
490
|
-
})
|
|
491
|
-
accum[fieldToInclude.alias] = sysAccum
|
|
492
|
-
}
|
|
493
|
-
} else if (fieldToInclude.name === '__typename') {
|
|
494
|
-
// field namespaces are one level deeper than what we need, so grab the first
|
|
495
|
-
// one and remove the last string on the namespace
|
|
496
|
-
accum[fieldToInclude.alias] = NAMER.dataTypeName(
|
|
497
|
-
fields[0].namespace.slice(0, fields[0].namespace.length - 1)
|
|
498
|
-
)
|
|
499
|
-
} else if (fieldToInclude.name === '_values') {
|
|
500
|
-
if (fieldToInclude.alias !== '_internalValues') {
|
|
501
|
-
accum[fieldToInclude.alias] = values
|
|
502
|
-
}
|
|
503
|
-
} else {
|
|
504
|
-
}
|
|
505
|
-
} else {
|
|
506
|
-
const result = resolveField({
|
|
507
|
-
id,
|
|
508
|
-
field,
|
|
509
|
-
sys,
|
|
510
|
-
value: values[field.name],
|
|
511
|
-
fieldsToInclude: fieldsToInclude.find(({ name }) => name === field.name)
|
|
512
|
-
?.fields,
|
|
513
|
-
context,
|
|
514
|
-
})
|
|
515
|
-
if (result) {
|
|
516
|
-
accum[fieldToInclude.alias] = result
|
|
517
|
-
}
|
|
506
|
+
fields.forEach((field) => {
|
|
507
|
+
const v = values[field.name]
|
|
508
|
+
if (!v) {
|
|
509
|
+
return
|
|
518
510
|
}
|
|
511
|
+
accum[field.name] = resolveFieldValue({
|
|
512
|
+
field,
|
|
513
|
+
value: v,
|
|
514
|
+
tinaSchema,
|
|
515
|
+
})
|
|
519
516
|
})
|
|
520
|
-
|
|
521
|
-
return accum
|
|
517
|
+
return accum as T & { __typename?: string }
|
|
522
518
|
}
|
|
523
|
-
const
|
|
524
|
-
id,
|
|
519
|
+
const resolveFieldValue = ({
|
|
525
520
|
field,
|
|
526
|
-
sys,
|
|
527
521
|
value,
|
|
528
|
-
|
|
529
|
-
context,
|
|
522
|
+
tinaSchema,
|
|
530
523
|
}: {
|
|
531
|
-
id: string
|
|
532
524
|
field: TinaFieldEnriched
|
|
533
|
-
sys: Record<string, unknown>
|
|
534
525
|
value: unknown
|
|
535
|
-
|
|
536
|
-
context: ContextFrom<typeof queryMachine>
|
|
526
|
+
tinaSchema: TinaSchema
|
|
537
527
|
}) => {
|
|
538
528
|
switch (field.type) {
|
|
539
|
-
case '
|
|
540
|
-
if (
|
|
541
|
-
return
|
|
542
|
-
}
|
|
543
|
-
if (typeof value === 'string') {
|
|
544
|
-
const doc = context.documentMap[value]
|
|
545
|
-
const docContext = doc?.ref?.getSnapshot()?.context
|
|
546
|
-
const form = docContext?.form
|
|
547
|
-
if (!form) {
|
|
548
|
-
throw new QueryError(
|
|
549
|
-
`Unable to resolve form for document`,
|
|
550
|
-
value,
|
|
551
|
-
true
|
|
552
|
-
)
|
|
553
|
-
}
|
|
554
|
-
const _internalSys = docContext.data?._internalSys
|
|
555
|
-
if (!_internalSys) {
|
|
556
|
-
throw new Error(`No system information found for document ${id}`)
|
|
557
|
-
}
|
|
558
|
-
return resolveForm({
|
|
559
|
-
id: value,
|
|
560
|
-
fields: form.fields,
|
|
561
|
-
sys: _internalSys,
|
|
562
|
-
values: form.values,
|
|
563
|
-
fieldsToInclude,
|
|
564
|
-
context,
|
|
565
|
-
})
|
|
566
|
-
}
|
|
567
|
-
throw new Error(`Unexpected value for type "reference"`)
|
|
568
|
-
case 'object':
|
|
569
|
-
if (field.fields) {
|
|
570
|
-
if (typeof field.fields === 'string') {
|
|
571
|
-
throw new Error('Global templates not supported')
|
|
572
|
-
}
|
|
573
|
-
field.fields
|
|
529
|
+
case 'object': {
|
|
530
|
+
if (field.templates) {
|
|
574
531
|
if (field.list) {
|
|
575
532
|
if (Array.isArray(value)) {
|
|
576
533
|
return value.map((item) => {
|
|
577
|
-
|
|
534
|
+
const template = field.templates[item._template]
|
|
535
|
+
if (typeof template === 'string') {
|
|
578
536
|
throw new Error('Global templates not supported')
|
|
579
537
|
}
|
|
580
|
-
return
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
538
|
+
return {
|
|
539
|
+
__typename: NAMER.dataTypeName(template.namespace),
|
|
540
|
+
...resolveFormValue({
|
|
541
|
+
fields: template.fields,
|
|
542
|
+
values: item,
|
|
543
|
+
tinaSchema,
|
|
544
|
+
}),
|
|
545
|
+
}
|
|
588
546
|
})
|
|
589
547
|
}
|
|
590
548
|
} else {
|
|
591
|
-
|
|
592
|
-
id,
|
|
593
|
-
fields: field.fields,
|
|
594
|
-
sys,
|
|
595
|
-
values: value,
|
|
596
|
-
fieldsToInclude,
|
|
597
|
-
context,
|
|
598
|
-
})
|
|
549
|
+
// not implemented
|
|
599
550
|
}
|
|
600
551
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
552
|
+
|
|
553
|
+
const templateFields = field.fields
|
|
554
|
+
if (typeof templateFields === 'string') {
|
|
555
|
+
throw new Error('Global templates not supported')
|
|
556
|
+
}
|
|
557
|
+
if (!templateFields) {
|
|
558
|
+
throw new Error(`Expected to find sub-fields on field ${field.name}`)
|
|
559
|
+
}
|
|
560
|
+
if (field.list) {
|
|
561
|
+
if (Array.isArray(value)) {
|
|
609
562
|
return value.map((item) => {
|
|
610
|
-
let t: Template<true>
|
|
611
|
-
Object.entries(field.templates).forEach(([name, template]) => {
|
|
612
|
-
if (name === item._template) {
|
|
613
|
-
if (typeof template === 'string') {
|
|
614
|
-
throw new Error('Global templates not supported')
|
|
615
|
-
}
|
|
616
|
-
t = template
|
|
617
|
-
}
|
|
618
|
-
})
|
|
619
563
|
return {
|
|
620
|
-
|
|
621
|
-
...
|
|
622
|
-
|
|
623
|
-
fields: t.fields,
|
|
624
|
-
sys,
|
|
564
|
+
__typename: NAMER.dataTypeName(field.namespace),
|
|
565
|
+
...resolveFormValue({
|
|
566
|
+
fields: templateFields,
|
|
625
567
|
values: item,
|
|
626
|
-
|
|
627
|
-
context,
|
|
568
|
+
tinaSchema,
|
|
628
569
|
}),
|
|
629
570
|
}
|
|
630
571
|
})
|
|
631
|
-
}
|
|
632
|
-
|
|
572
|
+
}
|
|
573
|
+
} else {
|
|
574
|
+
return {
|
|
575
|
+
__typename: NAMER.dataTypeName(field.namespace),
|
|
576
|
+
...resolveFormValue({
|
|
577
|
+
fields: templateFields,
|
|
578
|
+
values: value as any,
|
|
579
|
+
tinaSchema,
|
|
580
|
+
}),
|
|
633
581
|
}
|
|
634
582
|
}
|
|
635
|
-
|
|
583
|
+
}
|
|
584
|
+
default: {
|
|
636
585
|
return value
|
|
586
|
+
}
|
|
637
587
|
}
|
|
638
588
|
}
|
package/appFiles/src/preview.tsx
CHANGED
|
@@ -80,6 +80,8 @@ const QueryMachine = (props: {
|
|
|
80
80
|
queryMachine.withContext({
|
|
81
81
|
...initialContext,
|
|
82
82
|
cms,
|
|
83
|
+
// Enable registration of sub forms
|
|
84
|
+
// registerSubForms: true,
|
|
83
85
|
// @ts-ignore FIXME: add formifyCallback args to Config type
|
|
84
86
|
formifyCallback: props.formifyCallback,
|
|
85
87
|
}),
|
package/dist/test-utils.js
CHANGED
|
@@ -270,8 +270,28 @@ var formify = async ({
|
|
|
270
270
|
var node = G.parse(`
|
|
271
271
|
query Sample {
|
|
272
272
|
...on Document {
|
|
273
|
+
_internalValues: _values
|
|
273
274
|
_internalSys: _sys {
|
|
275
|
+
breadcrumbs
|
|
276
|
+
basename
|
|
277
|
+
filename
|
|
274
278
|
path
|
|
279
|
+
extension
|
|
280
|
+
relativePath
|
|
281
|
+
title
|
|
282
|
+
template
|
|
283
|
+
collection {
|
|
284
|
+
name
|
|
285
|
+
slug
|
|
286
|
+
label
|
|
287
|
+
path
|
|
288
|
+
format
|
|
289
|
+
matches
|
|
290
|
+
templates
|
|
291
|
+
fields
|
|
292
|
+
__typename
|
|
293
|
+
}
|
|
294
|
+
__typename
|
|
275
295
|
}
|
|
276
296
|
}
|
|
277
297
|
}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/app",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.27",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"@types/react": "17.0.2",
|
|
38
38
|
"@types/react-dom": "17.0.2",
|
|
39
39
|
"@tinacms/scripts": "0.51.3",
|
|
40
|
-
"tinacms": "0.70.
|
|
41
|
-
"@tinacms/mdx": "0.61.
|
|
40
|
+
"tinacms": "0.70.1",
|
|
41
|
+
"@tinacms/mdx": "0.61.16",
|
|
42
42
|
"jest": "^27.0.6"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|