tinacms 1.2.1 → 1.3.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.
package/dist/index.es.js CHANGED
@@ -1,16 +1,15 @@
1
- import { useCMS, Form, GlobalFormPlugin, EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, Nav, BranchBanner, LocalWarning, BillingWarning, Select, Input, ReactDateTimeWithStyles, textFieldClasses, Toggle, OverflowMenu, CursorPaginator, PopupModal, BaseTextField, wrapFieldsWithMeta, FormStatus, FormBuilder } from "@tinacms/toolkit";
1
+ import { z } from "zod";
2
+ import { EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, useCMS, Nav, BranchBanner, LocalWarning, BillingWarning, Select, Input, ReactDateTimeWithStyles, textFieldClasses, Toggle, OverflowMenu, CursorPaginator, PopupModal, BaseTextField, Form, wrapFieldsWithMeta, FormStatus, FormBuilder } from "@tinacms/toolkit";
2
3
  export * from "@tinacms/toolkit";
3
4
  export { MdxFieldPluginExtendible } from "@tinacms/toolkit";
4
- import * as G from "graphql";
5
- import { TypeInfo, visit, visitWithTypeInfo, getNamedType, GraphQLObjectType, isLeafType, GraphQLUnionType, isScalarType as isScalarType$1, getIntrospectionQuery, buildClientSchema, print, parse } from "graphql";
6
- import set from "lodash.set";
7
- import React, { useState, useCallback, useEffect, Fragment, useMemo } from "react";
8
- import { getIn, setIn } from "final-form";
9
- import { resolveForm, TinaSchema, addNamespaceToSchema, parseURL, validateSchema } from "@tinacms/schema-tools";
10
- export { NAMER, resolveForm } from "@tinacms/schema-tools";
5
+ import { getIntrospectionQuery, buildClientSchema, print, parse, buildSchema } from "graphql";
11
6
  import gql$1 from "graphql-tag";
7
+ import { TinaSchema, addNamespaceToSchema, parseURL, resolveForm, validateSchema } from "@tinacms/schema-tools";
8
+ export { NAMER, resolveForm } from "@tinacms/schema-tools";
9
+ import React, { useState, useCallback, useEffect, Fragment, useMemo } from "react";
12
10
  import * as yup from "yup";
13
- import { setEditing, TinaDataContext, EditContext, useEditState } from "@tinacms/sharedctx";
11
+ import { setEditing, useEditState } from "@tinacms/sharedctx";
12
+ import { diff } from "@graphql-inspector/core";
14
13
  import { NavLink, useSearchParams, useNavigate, useParams, useLocation, Link, HashRouter, Routes, Route } from "react-router-dom";
15
14
  import { Transition, Menu } from "@headlessui/react";
16
15
  import { useWindowWidth } from "@react-hook/window-size";
@@ -23,2097 +22,60 @@ const TINA_LOGIN_EVENT = "tinaCloudLogin";
23
22
  const AUTH_TOKEN_KEY = "tinacms-auth";
24
23
  const authenticate = (clientId, frontendUrl) => {
25
24
  return new Promise((resolve) => {
26
- let authTab;
27
- window.addEventListener("message", function(e) {
28
- if (e.data.source === TINA_LOGIN_EVENT) {
29
- if (authTab) {
30
- authTab.close();
31
- }
32
- resolve({
33
- id_token: e.data.id_token,
34
- access_token: e.data.access_token,
35
- refresh_token: e.data.refresh_token
36
- });
37
- }
38
- });
39
- const origin = `${window.location.protocol}//${window.location.host}`;
40
- authTab = popupWindow(`${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`, "_blank", window, 1e3, 700);
41
- });
42
- };
43
- const formify$1 = (query, schema) => {
44
- const typeInfo = new TypeInfo(schema);
45
- const pathsToPopulate = [];
46
- const visitor = {
47
- leave(node2, key, parent, path, ancestors) {
48
- const type = typeInfo.getType();
49
- if (type) {
50
- const namedType = getNamedType(type);
51
- if (namedType instanceof GraphQLObjectType) {
52
- const hasNodeInterface = !!namedType.getInterfaces().find((i) => i.name === "Node");
53
- if (hasNodeInterface) {
54
- if (typeof path[path.length - 1] === "number") {
55
- assertIsObjectType(namedType);
56
- const valuesNode = namedType.getFields().values;
57
- const namedValuesNode = getNamedType(valuesNode.type);
58
- const pathForValues = [...path];
59
- pathForValues.push("selectionSet");
60
- pathForValues.push("selections");
61
- const valuesAst = buildValuesForType(namedValuesNode);
62
- pathForValues.push(100);
63
- const formNode = namedType.getFields().form;
64
- const namedFormNode = getNamedType(formNode.type);
65
- const pathForForm = [...path];
66
- pathForForm.push("selectionSet");
67
- pathForForm.push("selections");
68
- const formAst = buildFormForType(namedFormNode);
69
- pathForForm.push(101);
70
- const sysNode = namedType.getFields().sys;
71
- const namedSysNode = getNamedType(sysNode.type);
72
- const pathForSys = [...path];
73
- pathForSys.push("selectionSet");
74
- pathForSys.push("selections");
75
- const sysAst = buildSysForType(namedSysNode);
76
- pathForSys.push(102);
77
- pathsToPopulate.push({
78
- path: path.map((p) => p.toString()).join("-"),
79
- paths: [
80
- {
81
- path: pathForValues.map((p) => p.toString()),
82
- ast: valuesAst
83
- },
84
- {
85
- path: pathForForm.map((p) => p.toString()),
86
- ast: formAst
87
- },
88
- {
89
- path: pathForSys.map((p) => p.toString()),
90
- ast: sysAst
91
- }
92
- ]
93
- });
94
- }
95
- }
96
- }
97
- }
98
- }
99
- };
100
- visit(query, visitWithTypeInfo(typeInfo, visitor));
101
- const topLevelPaths = pathsToPopulate.filter((p, i) => {
102
- const otherPaths = pathsToPopulate.filter((_, index) => index !== i);
103
- const isChildOfOtherPaths = otherPaths.some((op) => {
104
- if (p.path.startsWith(op.path)) {
105
- return true;
106
- } else {
107
- return false;
108
- }
109
- });
110
- if (isChildOfOtherPaths) {
111
- return false;
112
- } else {
113
- return true;
114
- }
115
- });
116
- topLevelPaths.map((p) => {
117
- p.paths.map((pathNode) => {
118
- set(query, pathNode.path, pathNode.ast);
119
- });
120
- });
121
- return query;
122
- };
123
- const buildSysForType = (type) => {
124
- assertIsObjectType(type);
125
- return {
126
- kind: "Field",
127
- alias: {
128
- kind: "Name",
129
- value: "_internalSys"
130
- },
131
- name: {
132
- kind: "Name",
133
- value: "sys"
134
- },
135
- selectionSet: {
136
- kind: "SelectionSet",
137
- selections: buildSelectionsFields(Object.values(type.getFields()), (fields) => {
138
- return {
139
- continue: true,
140
- filteredFields: fields.filter((field) => field.name !== "documents")
141
- };
142
- })
143
- }
144
- };
145
- };
146
- const buildValuesForType = (type) => {
147
- try {
148
- assertIsUnionType(type);
149
- return {
150
- kind: "Field",
151
- name: {
152
- kind: "Name",
153
- value: "values"
154
- },
155
- selectionSet: {
156
- kind: "SelectionSet",
157
- selections: buildSelectionInlineFragments(type.getTypes())
158
- }
159
- };
160
- } catch (e) {
161
- return {
162
- kind: "Field",
163
- name: {
164
- kind: "Name",
165
- value: "values"
166
- }
167
- };
168
- }
169
- };
170
- const buildFormForType = (type) => {
171
- try {
172
- assertIsUnionType(type);
173
- return {
174
- kind: "Field",
175
- name: {
176
- kind: "Name",
177
- value: "form"
178
- },
179
- selectionSet: {
180
- kind: "SelectionSet",
181
- selections: buildSelectionInlineFragments(type.getTypes())
182
- }
183
- };
184
- } catch (e) {
185
- return {
186
- kind: "Field",
187
- name: {
188
- kind: "Name",
189
- value: "form"
190
- }
191
- };
192
- }
193
- };
194
- const buildSelectionInlineFragments = (types, callback) => {
195
- return types.map((type) => {
196
- return {
197
- kind: "InlineFragment",
198
- typeCondition: {
199
- kind: "NamedType",
200
- name: {
201
- kind: "Name",
202
- value: type.name
203
- }
204
- },
205
- selectionSet: {
206
- kind: "SelectionSet",
207
- selections: [
208
- ...Object.values(type.getFields()).map((field) => {
209
- const namedType = getNamedType(field.type);
210
- if (isLeafType(namedType)) {
211
- return {
212
- kind: "Field",
213
- name: {
214
- kind: "Name",
215
- value: field.name
216
- }
217
- };
218
- } else if (namedType instanceof GraphQLUnionType) {
219
- return {
220
- kind: "Field",
221
- name: {
222
- kind: "Name",
223
- value: field.name
224
- },
225
- selectionSet: {
226
- kind: "SelectionSet",
227
- selections: [
228
- ...buildSelectionInlineFragments(namedType.getTypes(), callback)
229
- ]
230
- }
231
- };
232
- } else if (namedType instanceof GraphQLObjectType) {
233
- return {
234
- kind: "Field",
235
- name: {
236
- kind: "Name",
237
- value: field.name
238
- },
239
- selectionSet: {
240
- kind: "SelectionSet",
241
- selections: [
242
- ...buildSelectionsFields(Object.values(namedType.getFields()), callback)
243
- ]
244
- }
245
- };
246
- } else {
247
- throw new Error(`Unexpected GraphQL type for field ${namedType.name}`);
248
- }
249
- })
250
- ]
251
- }
252
- };
253
- });
254
- };
255
- const buildSelectionsFields = (fields, callback) => {
256
- let filteredFields = fields;
257
- if (callback) {
258
- const result = callback(fields);
259
- if (!result.continue) {
260
- if (fields.every((field) => {
261
- return !isScalarType$1(getNamedType(field.type));
262
- })) {
263
- return [
264
- {
265
- kind: "Field",
266
- name: {
267
- kind: "Name",
268
- value: "__typename"
269
- }
270
- }
271
- ];
272
- }
273
- return buildSelectionsFields(result.filteredFields.filter((field) => {
274
- if (isScalarType$1(getNamedType(field.type))) {
275
- return true;
276
- }
277
- return false;
278
- }));
279
- } else {
280
- filteredFields = result.filteredFields;
281
- }
282
- }
283
- return filteredFields.map((field) => {
284
- const namedType = getNamedType(field.type);
285
- if (isLeafType(namedType)) {
286
- return {
287
- kind: "Field",
288
- name: {
289
- kind: "Name",
290
- value: field.name
291
- }
292
- };
293
- } else if (namedType instanceof GraphQLUnionType) {
294
- return {
295
- kind: "Field",
296
- name: {
297
- kind: "Name",
298
- value: field.name
299
- },
300
- selectionSet: {
301
- kind: "SelectionSet",
302
- selections: [
303
- ...buildSelectionInlineFragments(namedType.getTypes(), callback)
304
- ]
305
- }
306
- };
307
- } else if (namedType instanceof GraphQLObjectType) {
308
- return {
309
- kind: "Field",
310
- name: {
311
- kind: "Name",
312
- value: field.name
313
- },
314
- selectionSet: {
315
- kind: "SelectionSet",
316
- selections: [
317
- ...buildSelectionsFields(Object.values(namedType.getFields()), callback)
318
- ]
319
- }
320
- };
321
- } else {
322
- return {
323
- kind: "Field",
324
- name: {
325
- kind: "Name",
326
- value: field.name
327
- },
328
- selectionSet: {
329
- kind: "SelectionSet",
330
- selections: []
331
- }
332
- };
333
- }
334
- });
335
- };
336
- function assertIsObjectType(type) {
337
- if (type instanceof GraphQLObjectType)
338
- ;
339
- else {
340
- throw new Error(`Expected an instance of GraphQLObjectType for type ${type.name}`);
341
- }
342
- }
343
- function assertIsUnionType(type) {
344
- if (type instanceof GraphQLUnionType)
345
- ;
346
- else {
347
- throw new Error(`Expected an instance of GraphQLUnionType for type ${type.name}`);
348
- }
349
- }
350
- const createClient = ({
351
- clientId,
352
- isLocalClient = true,
353
- branch,
354
- tinaioConfig,
355
- schema,
356
- apiUrl
357
- }) => {
358
- return isLocalClient ? new LocalClient({ customContentApiUrl: apiUrl, schema }) : new Client({
359
- clientId: clientId || "",
360
- branch: branch || "main",
361
- tokenStorage: "LOCAL_STORAGE",
362
- tinaioConfig,
363
- schema
364
- });
365
- };
366
- function assertShape(value, yupSchema, errorMessage) {
367
- const shape = yupSchema(yup);
368
- try {
369
- shape.validateSync(value);
370
- } catch (e) {
371
- const message = errorMessage || `Failed to assertShape - ${e.message}`;
372
- throw new Error(message);
373
- }
374
- }
375
- function safeAssertShape(value, yupSchema) {
376
- try {
377
- assertShape(value, yupSchema);
378
- return true;
379
- } catch (e) {
380
- return false;
381
- }
382
- }
383
- function useGraphqlForms({
384
- variables,
385
- onSubmit,
386
- query,
387
- formify: formify2,
388
- eventList
389
- }) {
390
- const cms = useCMS();
391
- const state = useFormify({
392
- query,
393
- cms,
394
- variables,
395
- formify: formify2,
396
- eventList,
397
- onSubmit
398
- });
399
- if (!query) {
400
- return [state.data, false];
401
- }
402
- return [state.data, state.status !== "done"];
403
- }
404
- const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
405
- const { _collection, __typename, _template, ...rest } = document;
406
- const params = transformParams(rest);
407
- const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
408
- return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
409
- };
410
- const transformParams = (data) => {
411
- if (["string", "number", "boolean"].includes(typeof data)) {
412
- return data;
413
- }
414
- if (Array.isArray(data)) {
415
- return data.map((item) => transformParams(item));
416
- }
417
- try {
418
- assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
419
- const { _template, __typename, ...rest } = data;
420
- const nested = transformParams(rest);
421
- return { [_template]: nested };
422
- } catch (e) {
423
- if (e.message === "Failed to assertShape - _template is a required field") {
424
- if (!data) {
425
- return [];
426
- }
427
- const accum = {};
428
- Object.entries(data).map(([keyName, value]) => {
429
- accum[keyName] = transformParams(value);
430
- });
431
- return accum;
432
- } else {
433
- if (!data) {
434
- return [];
435
- }
436
- throw e;
437
- }
438
- }
439
- };
440
- const generateFormCreators = (cms, showInSidebar, global) => {
441
- const createForm = (formConfig) => {
442
- const form = new Form(formConfig);
443
- if (showInSidebar) {
444
- if (global) {
445
- const options = typeof global === "boolean" ? [null, "fullscreen"] : [global.icon, global.layout];
446
- cms.plugins.add(new GlobalFormPlugin(form, ...options));
447
- } else {
448
- cms.forms.add(form);
449
- }
450
- }
451
- return form;
452
- };
453
- const createGlobalForm = (formConfig, options) => {
454
- const form = new Form(formConfig);
455
- if (showInSidebar) {
456
- cms.plugins.add(new GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
457
- }
458
- return form;
459
- };
460
- return { createForm, createGlobalForm };
461
- };
462
- const getValueForBlueprint = (state, path) => {
463
- const pathArray = path.split(".");
464
- let latest = state;
465
- pathArray.every((item, index) => {
466
- if (item === "[]") {
467
- const restOfItems = pathArray.slice(index + 1);
468
- if (latest) {
469
- const next = [];
470
- if (Array.isArray(latest)) {
471
- latest.forEach((latest2, index2) => {
472
- const res = getValueForBlueprint(latest2, restOfItems.join("."));
473
- next.push(res);
474
- });
475
- } else {
476
- throw new Error(`Expected value to be an array for "[]" item`);
477
- }
478
- if (next.length > 0) {
479
- latest = next;
480
- } else {
481
- latest = void 0;
482
- }
483
- }
484
- return false;
485
- } else {
486
- if (latest) {
487
- latest = latest[item];
488
- } else {
489
- latest = void 0;
490
- }
491
- }
492
- return true;
493
- });
494
- return latest;
495
- };
496
- const getFieldNameOrAlias = (fieldBlueprint) => {
497
- return fieldBlueprint.path[fieldBlueprint.path.length - 1].alias;
498
- };
499
- const spliceLocation = (string, location) => {
500
- const accum = [];
501
- let counter = 0;
502
- string.split(".").forEach((item) => {
503
- if (item === "[]") {
504
- accum.push(location[counter]);
505
- counter++;
506
- } else {
507
- accum.push(item);
508
- }
509
- });
510
- return accum.join(".");
511
- };
512
- const getPathToChange = (documentBlueprint, formNode, event) => {
513
- const fieldName = event.field.name;
514
- const location = [...formNode.location, ...stripIndices(fieldName)];
515
- const accum = [];
516
- let counter = 0;
517
- documentBlueprint.path.forEach((item) => {
518
- accum.push(item.alias);
519
- if (item.list) {
520
- if (location[counter] !== void 0) {
521
- accum.push(location[counter]);
522
- counter++;
523
- }
524
- }
525
- });
526
- return accum.join(".");
527
- };
528
- const buildForm = (doc, cms, formify2, showInSidebar = false, onSubmit) => {
529
- var _a;
530
- const id = doc._internalSys.path;
531
- const enrichedSchema = cms.api.tina.schema;
532
- const collection = enrichedSchema.getCollection(doc._internalSys.collection.name);
533
- const { createForm, createGlobalForm } = generateFormCreators(cms, showInSidebar, (_a = collection.ui) == null ? void 0 : _a.global);
534
- const SKIPPED = "SKIPPED";
535
- let form;
536
- let skipped;
537
- const skip = () => {
538
- skipped = SKIPPED;
539
- };
540
- if (skipped)
541
- return;
542
- const template = enrichedSchema.getTemplateForData({
543
- collection,
544
- data: doc._values
545
- });
546
- const formCommon = {
547
- id,
548
- label: id,
549
- initialValues: doc._values,
550
- onSubmit: async (payload) => {
551
- try {
552
- const params = transformDocumentIntoMutationRequestPayload(payload, {
553
- includeCollection: false,
554
- includeTemplate: !!collection.templates
555
- });
556
- const variables = { params };
557
- const mutationString = `#graphql
558
- mutation UpdateDocument($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) {
559
- updateDocument(collection: $collection, relativePath: $relativePath, params: $params) {
560
- __typename
561
- }
562
- }
563
- `;
564
- if (onSubmit) {
565
- onSubmit({
566
- queryString: mutationString,
567
- mutationString,
568
- variables: {
569
- collection: doc._internalSys.collection.name,
570
- relativePath: doc._internalSys.relativePath,
571
- params: { [doc._internalSys.collection.name]: variables }
572
- }
573
- });
574
- } else {
575
- try {
576
- await cms.api.tina.request(mutationString, {
577
- variables: {
578
- collection: doc._internalSys.collection.name,
579
- relativePath: doc._internalSys.relativePath,
580
- params: {
581
- [doc._internalSys.collection.name]: variables.params
582
- }
583
- }
584
- });
585
- cms.alerts.success("Document saved!");
586
- } catch (e) {
587
- cms.alerts.error("There was a problem saving your document.");
588
- console.error(e);
589
- }
590
- }
591
- } catch (e) {
592
- console.error(e);
593
- cms.alerts.error("There was a problem saving your document.");
594
- }
595
- }
596
- };
597
- let formConfig = {};
598
- const formInfo = resolveForm({
599
- collection,
600
- basename: collection.name,
601
- schema: enrichedSchema,
602
- template
603
- });
604
- formConfig = {
605
- label: formInfo.label,
606
- fields: formInfo.fields,
607
- ...formCommon
608
- };
609
- if (formify2) {
610
- form = formify2({
611
- formConfig,
612
- createForm,
613
- createGlobalForm,
614
- skip
615
- }, cms);
616
- } else {
617
- form = createForm(formConfig);
618
- }
619
- if (!(form instanceof Form)) {
620
- if (skipped === SKIPPED) {
621
- return;
622
- }
623
- throw new Error("formify must return a form or skip()");
624
- }
625
- return form;
626
- };
627
- const formNodeId = (formNode) => {
628
- return spliceLocation(formNode.documentBlueprintId, formNode.location) + formNode.documentFormId;
629
- };
630
- const formNodePath = (formNode) => {
631
- return spliceLocation(formNode.documentBlueprintId, formNode.location);
632
- };
633
- const formNodeNotIn = (formNode, formNodes) => {
634
- return !formNodes.find((fn) => formNodeId(fn) === formNodeId(formNode));
635
- };
636
- const sequential = async (items, callback) => {
637
- const accum = [];
638
- if (!items) {
639
- return [];
640
- }
641
- const reducePromises = async (previous, endpoint) => {
642
- const prev = await previous;
643
- if (prev) {
644
- accum.push(prev);
645
- }
646
- return callback(endpoint, accum.length);
647
- };
648
- const result = await items.reduce(reducePromises, Promise.resolve());
649
- if (result) {
650
- accum.push(result);
651
- }
652
- return accum;
653
- };
654
- const getFormNodesStartingWith = (string, state) => {
655
- return state.formNodes.filter((subFormNode) => {
656
- return subFormNode.documentBlueprintId.startsWith(string);
657
- });
658
- };
659
- const getFormNodesForField = (fieldBlueprint, formNode, event, state) => {
660
- const pathToChange = getPathToChange(fieldBlueprint, formNode, event);
661
- const formNodes = getFormNodesStartingWith(fieldBlueprint.id, state);
662
- const eventLocation = [
663
- ...formNode.location,
664
- ...stripIndices(event.field.name)
665
- ];
666
- const existing = getIn(state.data, pathToChange);
667
- return { pathToChange, formNodes, eventLocation, existing };
668
- };
669
- const getBlueprintAliasPath = (blueprint) => {
670
- const namePath = [];
671
- const aliasPath = [];
672
- blueprint.path.forEach((p) => {
673
- namePath.push(p.name);
674
- aliasPath.push(p.alias);
675
- if (p.list) {
676
- namePath.push("[]");
677
- aliasPath.push("[]");
678
- }
679
- });
680
- return aliasPath.join(".");
681
- };
682
- const getBlueprintFieldsForEvent = (blueprint, event) => {
683
- return blueprint.fields.filter((fbp) => {
684
- if (getBlueprintNamePath(fbp) === getEventPath(event, blueprint)) {
685
- return true;
686
- }
687
- }).filter((fbp) => {
688
- return filterFieldBlueprintsByParentTypename(fbp, event.field.data.tinaField.parentTypename);
689
- });
690
- };
691
- const filterFieldBlueprintsByParentTypename = (fbp, typename) => {
692
- let lastDisambiguator;
693
- fbp.path.forEach((path) => {
694
- if (path.parentTypename) {
695
- lastDisambiguator = path.parentTypename;
696
- }
697
- });
698
- if (lastDisambiguator) {
699
- return typename === lastDisambiguator;
700
- } else {
701
- return true;
702
- }
703
- };
704
- const getBlueprintNamePath = (blueprint, disambiguator) => {
705
- const namePath = [];
706
- blueprint.path.forEach((p) => {
707
- if (disambiguator) {
708
- if (p.parentTypename) {
709
- namePath.push(p.parentTypename);
710
- }
711
- }
712
- namePath.push(p.name);
713
- if (p.list) {
714
- namePath.push("[]");
715
- }
716
- });
717
- return namePath.join(".");
718
- };
719
- const getEventPath = (event, blueprint) => {
720
- const stringArray = event.field.name.split(".");
721
- const eventPath = stringArray.map((item) => {
722
- if (isNaN(Number(item))) {
723
- return item;
724
- }
725
- return `[]`;
726
- }).join(".");
727
- const items = [blueprint.id, eventPath];
728
- const isList = event.field.data.tinaField.list;
729
- if (isList && !eventPath.endsWith("[]")) {
730
- items.push(`[]`);
731
- }
732
- return items.join(".");
733
- };
734
- const stripIndices = (string) => {
735
- const accum = [];
736
- const stringArray = string.split(".");
737
- stringArray.forEach((item) => {
738
- if (isNaN(item))
739
- ;
740
- else {
741
- accum.push(Number(item));
742
- }
743
- });
744
- return accum;
745
- };
746
- const replaceRealNum = (string) => {
747
- const stringArray = string.split(".");
748
- return stringArray.map((item) => {
749
- if (isNaN(item)) {
750
- return item;
751
- }
752
- return "[]";
753
- }).join(".");
754
- };
755
- const getMatchName = ({ field, prefix, blueprint }) => {
756
- const fieldName = field.list ? `${field.name}.[]` : field.name;
757
- const blueprintName = getBlueprintNamePath(blueprint);
758
- const extra = [];
759
- if (prefix) {
760
- extra.push(prefix);
761
- }
762
- const matchName = [blueprintName, ...extra, fieldName].join(".");
763
- return { matchName, fieldName };
764
- };
765
- const getFormNodesFromEvent = (state, event) => {
766
- const formNodes = state.formNodes.filter((formNode) => formNode.documentFormId === event.formId);
767
- return formNodes;
768
- };
769
- const printEvent = (event) => {
770
- var _a, _b;
771
- return {
772
- type: event.type,
773
- value: event.value,
774
- previousValue: event.previousValue,
775
- mutationType: event.mutationType,
776
- formId: event.formId,
777
- field: {
778
- data: (_a = event.field) == null ? void 0 : _a.data,
779
- name: (_b = event.field) == null ? void 0 : _b.name
780
- }
781
- };
782
- };
783
- const getFormNodeBlueprint = (formNode, state) => {
784
- return state.blueprints.find((d) => d.id === formNode.documentBlueprintId);
785
- };
786
- const getMoveMapping = (existing, from, to) => {
787
- const newOrderObject = {};
788
- if (from < to) {
789
- existing.map((_, i) => {
790
- if (i === from) {
791
- newOrderObject[i] = to;
792
- return;
793
- }
794
- if (i > from) {
795
- if (i < to) {
796
- newOrderObject[i] = i - 1;
797
- return;
798
- } else {
799
- if (i === to) {
800
- newOrderObject[i] = i - 1;
801
- return;
802
- }
803
- newOrderObject[i] = i;
804
- return;
805
- }
806
- } else {
807
- newOrderObject[i] = i;
808
- return;
809
- }
810
- });
811
- } else {
812
- existing.map((_, i) => {
813
- if (i === from) {
814
- newOrderObject[i] = to;
815
- return;
816
- }
817
- if (i > to) {
818
- if (i < from) {
819
- newOrderObject[i] = i + 1;
820
- return;
821
- } else {
822
- newOrderObject[i] = i;
823
- return;
824
- }
825
- } else {
826
- if (i === to) {
827
- newOrderObject[i] = i + 1;
828
- return;
829
- }
830
- newOrderObject[i] = i;
831
- return;
832
- }
833
- });
834
- }
835
- return newOrderObject;
836
- };
837
- const matchLocation = (eventLocation, formNode) => {
838
- return eventLocation.every((item, index) => item === formNode.location[index]);
839
- };
840
- const bumpLocation = (location) => {
841
- return location.map((item, index) => {
842
- if (index === location.length - 1) {
843
- return item + 1;
844
- }
845
- return item;
846
- });
847
- };
848
- const maybeLowerLocation = (location, at) => {
849
- return location.map((item, index) => {
850
- if (index === location.length - 1) {
851
- return item < at ? item : item - 1;
852
- }
853
- return item;
854
- });
855
- };
856
- const matchesAt = (location, at) => {
857
- let matches = false;
858
- location.map((item, index) => {
859
- if (index === location.length - 1) {
860
- if (item === at) {
861
- matches = true;
862
- }
863
- }
864
- });
865
- return matches;
866
- };
867
- const swapLocation = (location, mapping) => {
868
- return location.map((item, index) => {
869
- if (index === location.length - 1) {
870
- return mapping[item];
871
- }
872
- return item;
873
- });
874
- };
875
- const getSubFields = (changeSet) => {
876
- var _a;
877
- const fields = changeSet.fieldDefinition.fields ? changeSet.fieldDefinition.fields : changeSet.fieldDefinition.templates[changeSet.value[0]._template].fields;
878
- let __typename;
879
- if ((_a = changeSet.fieldDefinition) == null ? void 0 : _a.templates) {
880
- __typename = changeSet.fieldDefinition.typeMap[changeSet.value[0]._template];
881
- }
882
- return { fields, __typename };
883
- };
884
- const isFormifiableDocument = (t) => {
885
- const type = G.getNamedType(t);
886
- if (G.isUnionType(type)) {
887
- return type.getTypes().every((type2) => {
888
- return type2.getInterfaces().find((intfc) => intfc.name === "Node");
889
- });
890
- } else if (G.isObjectType(type)) {
891
- return !!type.getInterfaces().find((intfc) => intfc.name === "Node");
892
- } else {
893
- return false;
894
- }
895
- };
896
- const isScalarType = (t) => {
897
- const namedType = G.getNamedType(t);
898
- return G.isScalarType(namedType);
899
- };
900
- const isConnectionField = (t) => {
901
- const type = G.getNamedType(t);
902
- if (G.isObjectType(type)) {
903
- return !!type.getInterfaces().find((intfc) => intfc.name === "Connection");
904
- } else {
905
- throw new Error(`Expected GraphQLObjectType for isConnectionField check`);
906
- }
907
- };
908
- const getObjectField = (object, selectionNode) => {
909
- const namedType = G.getNamedType(object);
910
- ensureObjectOrInterfaceType(namedType);
911
- return namedType.getFields()[selectionNode.name.value];
912
- };
913
- const getSelectedUnionType = (unionType, selectionNode) => {
914
- const namedType = G.getNamedType(unionType);
915
- if (!G.isUnionType(namedType)) {
916
- return;
917
- }
918
- const types = namedType.getTypes();
919
- const typeCondition = selectionNode.typeCondition.name.value;
920
- let intfc;
921
- types.forEach((type) => {
922
- intfc = type.getInterfaces().find((intfc2) => intfc2.name === typeCondition);
923
- });
924
- if (intfc) {
925
- return intfc;
926
- }
927
- return namedType.getTypes().find((type) => type.name === typeCondition);
928
- };
929
- function isListType(type) {
930
- if (G.isListType(type)) {
931
- return true;
932
- } else if (G.isNonNullType(type)) {
933
- if (G.isListType(type.ofType)) {
934
- return true;
935
- }
936
- }
937
- return false;
938
- }
939
- function ensureObjectOrInterfaceType(type) {
940
- if (G.isInterfaceType(type) || G.isObjectType(type))
941
- ;
942
- else {
943
- console.log("Expected type to be GraphQLObjectType or GraphQLInterfaceType", type);
944
- throw new Error(`Expected type to be GraphQLObjectType or GraphQLInterfaceType`);
945
- }
946
- }
947
- function ensureOperationDefinition(type) {
948
- if (type.kind !== "OperationDefinition") {
949
- throw new Error(`Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`);
950
- }
951
- }
952
- function buildPath({
953
- fieldNode,
954
- type,
955
- parentTypename,
956
- path
957
- }) {
958
- const p = path || [];
959
- const list = isListType(type);
960
- const isNode = isFormifiableDocument(type);
961
- return [
962
- ...p,
963
- {
964
- name: fieldNode.name.value,
965
- alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
966
- parentTypename,
967
- list: !!list,
968
- isNode: !!isNode
969
- }
970
- ];
971
- }
972
- const node = G.parse(`
973
- query Sample {
974
- ...on Document {
975
- _internalSys: _sys {
976
- path
977
- relativePath
978
- collection {
979
- name
980
- }
981
- }
982
- _values
983
- }
984
- }`);
985
- const metaFields = node.definitions[0].selectionSet.selections;
986
- const getRelativeBlueprint = (path) => {
987
- let indexOfLastNode = 0;
988
- path.forEach((item, i) => {
989
- if (item.isNode) {
990
- if (i === path.length - 1)
991
- ;
992
- else {
993
- indexOfLastNode = i;
994
- }
995
- }
996
- });
997
- const documentBlueprintPath = path.slice(0, indexOfLastNode + 1);
998
- return getBlueprintNamePath({ path: documentBlueprintPath });
999
- };
1000
- const isSysField = (fieldNode) => {
1001
- if (fieldNode.name.value === "__typename") {
1002
- return true;
1003
- }
1004
- if (fieldNode.name.value === "_sys") {
1005
- return true;
1006
- }
1007
- if (fieldNode.name.value === "_values") {
1008
- return true;
1009
- }
1010
- if (fieldNode.name.value === "id") {
1011
- return true;
1012
- }
1013
- return false;
1014
- };
1015
- const getBlueprintId = (path) => {
1016
- const namePath = [];
1017
- const aliasPath = [];
1018
- path.forEach((p) => {
1019
- namePath.push(p.name);
1020
- aliasPath.push(p.alias);
1021
- if (p.list) {
1022
- namePath.push("[]");
1023
- aliasPath.push("[]");
1024
- }
1025
- });
1026
- return namePath.join(".");
1027
- };
1028
- const NOOP = "This is either an error or is not yet supported";
1029
- const UNEXPECTED = "Formify encountered an unexpected error, please contact support";
1030
- const EDGES_NODE_NAME = "edges";
1031
- const NODE_NAME = "node";
1032
- const COLLECTION_FIELD_NAME = "collection";
1033
- const COLLECTIONS_FIELD_NAME = "collections";
1034
- const COLLECTIONS_DOCUMENTS_NAME = "documents";
1035
- const formify = async ({
1036
- schema,
1037
- query,
1038
- getOptimizedQuery
1039
- }) => {
1040
- const blueprints = [];
1041
- const documentNode = G.parse(query);
1042
- const visitor = {
1043
- OperationDefinition: (node2) => {
1044
- if (!node2.name) {
1045
- return {
1046
- ...node2,
1047
- name: {
1048
- kind: "Name",
1049
- value: `QueryOperation`
1050
- }
1051
- };
1052
- }
1053
- return node2;
1054
- }
1055
- };
1056
- const documentNodeWithName = G.visit(documentNode, visitor);
1057
- const optimizedQuery = await getOptimizedQuery(documentNodeWithName);
1058
- const typeInfo = new G.TypeInfo(schema);
1059
- const formifyConnection = ({
1060
- parentType,
1061
- selectionNode,
1062
- path
1063
- }) => {
1064
- return {
1065
- ...selectionNode,
1066
- selectionSet: {
1067
- kind: "SelectionSet",
1068
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
1069
- switch (selectionNode2.kind) {
1070
- case "Field":
1071
- if (selectionNode2.name.value === EDGES_NODE_NAME) {
1072
- const edgeField = getObjectField(parentType, selectionNode2);
1073
- const edgesPath = buildPath({
1074
- fieldNode: selectionNode2,
1075
- type: edgeField.type,
1076
- path
1077
- });
1078
- return {
1079
- ...selectionNode2,
1080
- selectionSet: {
1081
- kind: "SelectionSet",
1082
- selections: selectionNode2.selectionSet.selections.map((subSelectionNode) => {
1083
- switch (subSelectionNode.kind) {
1084
- case "Field":
1085
- if (subSelectionNode.name.value === NODE_NAME) {
1086
- const nodeField = getObjectField(edgeField.type, subSelectionNode);
1087
- return formifyFieldNodeDocument({
1088
- fieldNode: subSelectionNode,
1089
- type: nodeField.type,
1090
- path: buildPath({
1091
- fieldNode: subSelectionNode,
1092
- type: nodeField.type,
1093
- path: edgesPath
1094
- }),
1095
- showInSidebar: false
1096
- });
1097
- } else {
1098
- return subSelectionNode;
1099
- }
1100
- default:
1101
- throw new FormifyError("NOOP");
1102
- }
1103
- })
1104
- }
1105
- };
1106
- }
1107
- return selectionNode2;
1108
- default:
1109
- throw new FormifyError("UNEXPECTED");
1110
- }
1111
- })
1112
- }
1113
- };
1114
- };
1115
- function formifyInlineFragmentDocument({
1116
- inlineFragmentNode,
1117
- type,
1118
- path,
1119
- showInSidebar = false
1120
- }) {
1121
- return formifyDocument({
1122
- selection: inlineFragmentNode,
1123
- type,
1124
- path,
1125
- showInSidebar
1126
- });
1127
- }
1128
- function formifyFieldNodeDocument({
1129
- fieldNode,
1130
- type,
1131
- path,
1132
- showInSidebar = false
1133
- }) {
1134
- return formifyDocument({ selection: fieldNode, type, path, showInSidebar });
1135
- }
1136
- function formifyDocument({
1137
- selection,
1138
- type,
1139
- path,
1140
- showInSidebar = false
1141
- }) {
1142
- let extraFields = [];
1143
- const hasDataJSONField = false;
1144
- let hasValuesField = false;
1145
- let shouldFormify = false;
1146
- selection.selectionSet.selections.forEach((selection2) => {
1147
- if (selection2.kind === "Field") {
1148
- shouldFormify = true;
1149
- if (selection2.name.value === "_values") {
1150
- hasValuesField = true;
1151
- }
1152
- }
1153
- });
1154
- if (shouldFormify) {
1155
- blueprints.push({
1156
- id: getBlueprintId(path),
1157
- path,
1158
- selection,
1159
- fields: [],
1160
- showInSidebar,
1161
- hasDataJSONField,
1162
- hasValuesField
1163
- });
1164
- extraFields = metaFields;
1165
- }
1166
- return {
1167
- ...selection,
1168
- selectionSet: {
1169
- kind: "SelectionSet",
1170
- selections: [
1171
- ...selection.selectionSet.selections.map((selectionNode) => {
1172
- switch (selectionNode.kind) {
1173
- case "InlineFragment": {
1174
- const namedType = G.getNamedType(type);
1175
- if (G.isInterfaceType(namedType)) {
1176
- const subType = schema.getImplementations(namedType).objects.find((item) => item.name === selectionNode.typeCondition.name.value);
1177
- return formifyInlineFragmentDocument({
1178
- inlineFragmentNode: selectionNode,
1179
- type: subType,
1180
- path,
1181
- showInSidebar: true
1182
- });
1183
- }
1184
- return formifyInlineFragmentNode({
1185
- inlineFragmentNode: selectionNode,
1186
- parentType: type,
1187
- path,
1188
- showInSidebar: true
1189
- });
1190
- }
1191
- case "Field": {
1192
- return formifyFieldNode({
1193
- fieldNode: selectionNode,
1194
- parentType: type,
1195
- path
1196
- });
1197
- }
1198
- default:
1199
- throw new FormifyError("UNEXPECTED");
1200
- }
1201
- }),
1202
- ...extraFields
1203
- ]
1204
- }
1205
- };
1206
- }
1207
- const formifyFieldNode = ({
1208
- fieldNode,
1209
- parentType,
1210
- path
1211
- }) => {
1212
- if (fieldNode.name.value === "__typename") {
1213
- return fieldNode;
1214
- }
1215
- const field = getObjectField(parentType, fieldNode);
1216
- if (!field) {
1217
- return fieldNode;
1218
- }
1219
- const fieldPath = buildPath({
1220
- fieldNode,
1221
- type: field.type,
1222
- parentTypename: G.getNamedType(parentType).name,
1223
- path
1224
- });
1225
- const blueprint = blueprints.find((blueprint2) => blueprint2.id === getRelativeBlueprint(fieldPath));
1226
- if (!blueprint) {
1227
- return fieldNode;
1228
- }
1229
- if (isSysField(fieldNode)) {
1230
- return fieldNode;
1231
- }
1232
- blueprint.fields.push({
1233
- id: getBlueprintId(fieldPath),
1234
- documentBlueprintId: blueprint.id,
1235
- path: fieldPath
1236
- });
1237
- if (isScalarType(field.type)) {
1238
- return fieldNode;
1239
- }
1240
- return {
1241
- ...fieldNode,
1242
- selectionSet: {
1243
- kind: "SelectionSet",
1244
- selections: [
1245
- ...fieldNode.selectionSet.selections.map((selectionNode) => {
1246
- switch (selectionNode.kind) {
1247
- case "Field": {
1248
- return formifyFieldNode({
1249
- fieldNode: selectionNode,
1250
- parentType: field.type,
1251
- path: fieldPath
1252
- });
1253
- }
1254
- case "InlineFragment": {
1255
- return formifyInlineFragmentNode({
1256
- inlineFragmentNode: selectionNode,
1257
- parentType: field.type,
1258
- path: fieldPath,
1259
- showInSidebar: false
1260
- });
1261
- }
1262
- default:
1263
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
1264
- }
1265
- })
1266
- ]
1267
- }
1268
- };
1269
- };
1270
- const formifyInlineFragmentNode = ({
1271
- inlineFragmentNode,
1272
- parentType,
1273
- path,
1274
- showInSidebar
1275
- }) => {
1276
- const type = getSelectedUnionType(parentType, inlineFragmentNode);
1277
- if (!type) {
1278
- return inlineFragmentNode;
1279
- }
1280
- if (isFormifiableDocument(type)) {
1281
- return formifyInlineFragmentDocument({
1282
- inlineFragmentNode,
1283
- type,
1284
- path,
1285
- showInSidebar
1286
- });
1287
- }
1288
- return {
1289
- ...inlineFragmentNode,
1290
- selectionSet: {
1291
- kind: "SelectionSet",
1292
- selections: inlineFragmentNode.selectionSet.selections.map((selectionNode) => {
1293
- switch (selectionNode.kind) {
1294
- case "Field":
1295
- return formifyFieldNode({
1296
- fieldNode: selectionNode,
1297
- parentType: type,
1298
- path
1299
- });
1300
- default:
1301
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
1302
- }
1303
- })
1304
- }
1305
- };
1306
- };
1307
- const formifiedQuery = {
1308
- kind: "Document",
1309
- definitions: optimizedQuery.definitions.map((definition) => {
1310
- typeInfo.enter(definition);
1311
- ensureOperationDefinition(definition);
1312
- const parentType = typeInfo.getType();
1313
- return {
1314
- ...definition,
1315
- selectionSet: {
1316
- kind: "SelectionSet",
1317
- selections: definition.selectionSet.selections.map((selectionNode) => {
1318
- switch (selectionNode.kind) {
1319
- case "Field":
1320
- const field = getObjectField(parentType, selectionNode);
1321
- const path = buildPath({
1322
- fieldNode: selectionNode,
1323
- type: field.type
1324
- });
1325
- if (isFormifiableDocument(field.type)) {
1326
- return formifyFieldNodeDocument({
1327
- fieldNode: selectionNode,
1328
- type: field.type,
1329
- path,
1330
- showInSidebar: true
1331
- });
1332
- } else if (isConnectionField(field.type)) {
1333
- return formifyConnection({
1334
- parentType: field.type,
1335
- selectionNode,
1336
- path
1337
- });
1338
- }
1339
- if (selectionNode.name.value === COLLECTION_FIELD_NAME || selectionNode.name.value === COLLECTIONS_FIELD_NAME) {
1340
- const path2 = buildPath({
1341
- fieldNode: selectionNode,
1342
- type: field.type
1343
- });
1344
- return {
1345
- ...selectionNode,
1346
- selectionSet: {
1347
- kind: "SelectionSet",
1348
- selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
1349
- switch (subSelectionNode.kind) {
1350
- case "Field":
1351
- if (subSelectionNode.name.value === COLLECTIONS_DOCUMENTS_NAME) {
1352
- const subField = getObjectField(field.type, subSelectionNode);
1353
- return formifyConnection({
1354
- parentType: subField.type,
1355
- selectionNode: subSelectionNode,
1356
- path: buildPath({
1357
- fieldNode: subSelectionNode,
1358
- type: subField.type,
1359
- path: path2
1360
- })
1361
- });
1362
- }
1363
- return subSelectionNode;
1364
- default:
1365
- throw new FormifyError("NOOP");
1366
- }
1367
- })
1368
- }
1369
- };
1370
- }
1371
- throw new FormifyError("NOOP");
1372
- default:
1373
- throw new FormifyError("UNEXPECTED");
1374
- }
1375
- })
1376
- }
1377
- };
1378
- })
1379
- };
1380
- return { formifiedQuery, blueprints };
1381
- };
1382
- class FormifyError extends Error {
1383
- constructor(code, details) {
1384
- let message;
1385
- switch (code) {
1386
- case "NOOP":
1387
- message = NOOP;
1388
- break;
1389
- case "UNEXPECTED":
1390
- message = UNEXPECTED;
1391
- break;
1392
- default:
1393
- message = "";
1394
- break;
1395
- }
1396
- super(`${message} ${details || ""}`);
1397
- this.name = "FormifyError";
1398
- }
1399
- }
1400
- const defaultState = {
1401
- status: "idle",
1402
- schema: void 0,
1403
- query: null,
1404
- queryString: null,
1405
- data: {},
1406
- changeSets: [],
1407
- count: 0,
1408
- blueprints: [],
1409
- formNodes: [],
1410
- documentForms: []
1411
- };
1412
- function reducer(state, action) {
1413
- var _a, _b, _c, _d;
1414
- switch (action.type) {
1415
- case "start":
1416
- return {
1417
- ...state,
1418
- ...defaultState,
1419
- query: action.value.query ? G.parse(action.value.query) : null,
1420
- queryString: action.value.query,
1421
- status: "initialized"
1422
- };
1423
- case "addDocumentBlueprints":
1424
- return {
1425
- ...state,
1426
- status: "formified",
1427
- blueprints: action.value.blueprints,
1428
- query: action.value.formifiedQuery
1429
- };
1430
- case "addOrReplaceDocumentFormNode": {
1431
- const existingDocumentForms = state.documentForms.filter((documentForm) => {
1432
- var _a2, _b2;
1433
- return documentForm.id !== ((_b2 = (_a2 = action.value) == null ? void 0 : _a2.documentForm) == null ? void 0 : _b2.id);
1434
- });
1435
- const existingDocumentFormNodes = state.formNodes.filter((formNode) => {
1436
- return formNodeId(formNode) !== formNodeId(action.value.formNode);
1437
- });
1438
- const newDocumentForms = [];
1439
- if ((_a = action.value) == null ? void 0 : _a.documentForm) {
1440
- newDocumentForms.push((_b = action.value) == null ? void 0 : _b.documentForm);
1441
- }
1442
- return {
1443
- ...state,
1444
- formNodes: [...existingDocumentFormNodes, action.value.formNode],
1445
- documentForms: [...existingDocumentForms, ...newDocumentForms]
1446
- };
1447
- }
1448
- case "onFieldChange": {
1449
- const event = action.value.event;
1450
- const changeSets = [];
1451
- const formNodesToReplace = [];
1452
- const formNodesToRemove = [];
1453
- const newFormNodes = [];
1454
- const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1455
- getFormNodesFromEvent(state, event).forEach((formNode) => {
1456
- const blueprint = getFormNodeBlueprint(formNode, state);
1457
- if (blueprint.hasValuesField) {
1458
- changeSets.push({
1459
- path: [formNodePath(formNode), "values"].join("."),
1460
- ...buildChangeSet(event, formNode),
1461
- value: form.values,
1462
- mutationType: {
1463
- type: "global"
1464
- }
1465
- });
1466
- }
1467
- if (blueprint.hasDataJSONField) {
1468
- changeSets.push({
1469
- path: [formNodePath(formNode), "dataJSON"].join("."),
1470
- ...buildChangeSet(event, formNode),
1471
- value: form.values,
1472
- mutationType: {
1473
- type: "global"
1474
- }
1475
- });
1476
- }
1477
- if (event.mutationType.type === "change") {
1478
- if (!action.value.form) {
1479
- getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1480
- const { pathToChange } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1481
- changeSets.push({
1482
- path: pathToChange,
1483
- ...buildChangeSet(event, formNode)
1484
- });
1485
- });
1486
- }
1487
- } else if (event.mutationType.type === "referenceChange") {
1488
- getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1489
- const {
1490
- pathToChange,
1491
- formNodes: subFormNodes,
1492
- eventLocation
1493
- } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1494
- if (action.value.form && state.blueprints.find((blueprint2) => blueprint2.id === fieldBlueprint.id)) {
1495
- const newFormNode = {
1496
- documentBlueprintId: fieldBlueprint.id,
1497
- documentFormId: action.value.form.id,
1498
- location: eventLocation
1499
- };
1500
- newFormNodes.push(newFormNode);
1501
- changeSets.push({
1502
- path: pathToChange,
1503
- ...buildChangeSet(event, newFormNode)
1504
- });
1505
- }
1506
- subFormNodes.forEach((subFormNode) => {
1507
- if (matchLocation(eventLocation, subFormNode)) {
1508
- if (!action.value.form) {
1509
- changeSets.push({
1510
- path: pathToChange,
1511
- ...buildChangeSet(event, subFormNode),
1512
- value: null
1513
- });
1514
- }
1515
- formNodesToReplace.push(subFormNode);
1516
- }
1517
- });
1518
- });
1519
- } else {
1520
- getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1521
- const { pathToChange, formNodes, existing, eventLocation } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1522
- if (event.mutationType.type === "insert") {
1523
- formNodes.forEach((subFormNode) => {
1524
- if (matchLocation(eventLocation, subFormNode)) {
1525
- newFormNodes.push({
1526
- ...subFormNode,
1527
- location: bumpLocation(subFormNode.location)
1528
- });
1529
- formNodesToReplace.push(subFormNode);
1530
- }
1531
- });
1532
- changeSets.push({
1533
- path: pathToChange,
1534
- ...buildChangeSet(event, formNode)
1535
- });
1536
- }
1537
- if (event.mutationType.type === "remove") {
1538
- const { at } = event.mutationType;
1539
- formNodes.forEach((subFormNode) => {
1540
- if (matchLocation(eventLocation, subFormNode)) {
1541
- if (matchesAt(subFormNode.location, at)) {
1542
- formNodesToRemove.push(subFormNode);
1543
- } else {
1544
- newFormNodes.push({
1545
- ...subFormNode,
1546
- location: maybeLowerLocation(subFormNode.location, at)
1547
- });
1548
- formNodesToReplace.push(subFormNode);
1549
- }
1550
- }
1551
- });
1552
- const next = existing.filter((_, index) => index !== at);
1553
- changeSets.push({
1554
- path: pathToChange,
1555
- ...buildChangeSet(event, formNode),
1556
- value: next
1557
- });
1558
- }
1559
- if (event.mutationType.type === "move") {
1560
- const next = [];
1561
- const { from, to } = event.mutationType;
1562
- const newOrderObject = getMoveMapping(existing, from, to);
1563
- formNodes.forEach((subFormNode) => {
1564
- if (matchLocation(eventLocation, subFormNode)) {
1565
- newFormNodes.push({
1566
- ...subFormNode,
1567
- location: swapLocation(subFormNode.location, newOrderObject)
1568
- });
1569
- formNodesToReplace.push(subFormNode);
1570
- }
1571
- });
1572
- Object.values(newOrderObject).forEach((orderIndex, index) => {
1573
- next[orderIndex] = existing[index];
1574
- });
1575
- changeSets.push({
1576
- path: pathToChange,
1577
- ...buildChangeSet(event, formNode),
1578
- value: next
1579
- });
1580
- }
1581
- });
1582
- }
1583
- });
1584
- const existingDocumentForms = state.documentForms.filter((documentForm) => {
1585
- var _a2;
1586
- return documentForm.id !== ((_a2 = action.value.form) == null ? void 0 : _a2.id);
1587
- });
1588
- const newDocumentForms = [];
1589
- if ((_c = action.value) == null ? void 0 : _c.form) {
1590
- newDocumentForms.push((_d = action.value) == null ? void 0 : _d.form);
1591
- }
1592
- return {
1593
- ...state,
1594
- changeSets,
1595
- formNodes: [
1596
- ...state.formNodes.filter((formNode) => formNodeNotIn(formNode, formNodesToReplace)).filter((formNode) => formNodeNotIn(formNode, formNodesToRemove)),
1597
- ...newFormNodes
1598
- ],
1599
- documentForms: [...existingDocumentForms, ...newDocumentForms]
1600
- };
1601
- }
1602
- case "formOnReset": {
1603
- const { event } = action.value;
1604
- const changeSets = [];
1605
- const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1606
- state.formNodes.filter((fn) => fn.documentFormId === (form == null ? void 0 : form.id)).forEach((formNode) => {
1607
- const blueprint = getFormNodeBlueprint(formNode, state);
1608
- if (blueprint.hasValuesField) {
1609
- changeSets.push({
1610
- path: [formNodePath(formNode), "_values"].join("."),
1611
- ...buildChangeSet(event, formNode)
1612
- });
1613
- }
1614
- changeSets.push({
1615
- path: [formNodePath(formNode)].join("."),
1616
- ...buildChangeSet(event, formNode)
1617
- });
1618
- });
1619
- return { ...state, changeSets };
1620
- }
1621
- case "ready":
1622
- return { ...state, status: "ready" };
1623
- case "done":
1624
- return { ...state, status: "done" };
1625
- case "setData":
1626
- return { ...state, data: action.value };
1627
- case "setIn": {
1628
- let newData;
1629
- if (action.value.displaceIndex) {
1630
- const existing = getIn(state.data, action.value.path) || [];
1631
- newData = setIn(state.data, action.value.path, [
1632
- action.value.value,
1633
- ...existing
1634
- ]);
1635
- } else {
1636
- newData = setIn(state.data, action.value.path, action.value.value);
1637
- }
1638
- const changeSets = state.changeSets.filter((cs) => cs.path !== action.value.path);
1639
- return {
1640
- ...state,
1641
- data: newData,
1642
- changeSets
1643
- };
1644
- }
1645
- default:
1646
- return state;
1647
- }
1648
- }
1649
- const buildChangeSet = (event, formNode) => {
1650
- var _a, _b, _c;
1651
- return {
1652
- fieldDefinition: (_b = (_a = event.field) == null ? void 0 : _a.data) == null ? void 0 : _b.tinaField,
1653
- name: (_c = event.field) == null ? void 0 : _c.name,
1654
- formId: event.formId,
1655
- mutationType: event.mutationType,
1656
- value: event.value,
1657
- formNode
1658
- };
1659
- };
1660
- const useFormify = ({
1661
- query,
1662
- cms,
1663
- variables,
1664
- onSubmit,
1665
- formify: formifyFunc,
1666
- eventList
1667
- }) => {
1668
- const formIds = React.useRef([]);
1669
- const [state, dispatch] = React.useReducer(reducer, {
1670
- status: "idle",
1671
- schema: void 0,
1672
- query: query ? G.parse(query) : null,
1673
- queryString: query,
1674
- data: {},
1675
- changeSets: [],
1676
- count: 0,
1677
- blueprints: [],
1678
- formNodes: [],
1679
- documentForms: []
1680
- });
1681
- React.useEffect(() => {
1682
- if (query) {
1683
- dispatch({ type: "start", value: { query } });
1684
- formIds.current.forEach((formId) => {
1685
- const form = cms.forms.find(formId);
1686
- if (form) {
1687
- cms.plugins.remove(form);
1688
- }
1689
- });
1690
- }
1691
- }, [query, JSON.stringify(variables)]);
1692
- React.useEffect(() => {
1693
- if (state.status === "initialized") {
1694
- cms.api.tina.request(query, { variables }).then((res) => {
1695
- delete res.paths;
1696
- dispatch({ type: "setData", value: res });
1697
- });
1698
- }
1699
- }, [state.status]);
1700
- React.useEffect(() => {
1701
- const run = async () => {
1702
- const schema = await cms.api.tina.getSchema();
1703
- const result = await formify({
1704
- schema,
1705
- query,
1706
- getOptimizedQuery: cms.api.tina.getOptimizedQuery
1707
- });
1708
- dispatch({
1709
- type: "addDocumentBlueprints",
1710
- value: result
1711
- });
1712
- };
1713
- if (state.status === "initialized") {
1714
- run();
1715
- }
1716
- }, [state.status]);
1717
- React.useEffect(() => {
1718
- const run = async () => {
1719
- const result = await cms.api.tina.request(G.print(state.query), {
1720
- variables
1721
- });
1722
- state.blueprints.map((blueprint) => {
1723
- const responseAtBlueprint = getValueForBlueprint(result, getBlueprintAliasPath(blueprint));
1724
- const location = [];
1725
- const findFormNodes = (res, location2) => {
1726
- if (Array.isArray(res)) {
1727
- res.forEach((item, index) => {
1728
- if (Array.isArray(item)) {
1729
- findFormNodes(item, [...location2, index]);
1730
- } else {
1731
- if (item) {
1732
- const form = buildForm(item, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
1733
- const formNode = buildFormNode(blueprint, form, [
1734
- ...location2,
1735
- index
1736
- ]);
1737
- dispatch({
1738
- type: "addOrReplaceDocumentFormNode",
1739
- value: {
1740
- formNode,
1741
- documentForm: form
1742
- }
1743
- });
1744
- }
1745
- }
1746
- });
1747
- } else {
1748
- if (res) {
1749
- const form = buildForm(res, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
1750
- const formNode = buildFormNode(blueprint, form, location2);
1751
- dispatch({
1752
- type: "addOrReplaceDocumentFormNode",
1753
- value: {
1754
- formNode,
1755
- documentForm: form
1756
- }
1757
- });
1758
- }
1759
- }
1760
- };
1761
- findFormNodes(responseAtBlueprint, location);
1762
- });
1763
- dispatch({ type: "ready" });
1764
- };
1765
- if (state.status === "formified") {
1766
- run();
1767
- }
1768
- }, [state.status]);
1769
- React.useEffect(() => {
1770
- if (state.status === "ready") {
1771
- cms.events.subscribe(`forms:reset`, (event) => {
1772
- if (eventList) {
1773
- eventList.push(printEvent(event));
1774
- }
1775
- dispatch({ type: "formOnReset", value: { event } });
1776
- });
1777
- cms.events.subscribe(`forms:fields:onChange`, async (event) => {
1778
- if (eventList) {
1779
- eventList.push(printEvent(event));
1780
- }
1781
- if (event.field.data.tinaField.type === "reference") {
1782
- let form;
1783
- if (event.value && typeof event.value === "string") {
1784
- const existingForm = cms.forms.find(event.value);
1785
- if (existingForm) {
1786
- form = existingForm;
1787
- } else {
1788
- const formInfo = await cms.api.tina.request(`#graphql
1789
- query Node($id: String!) {
1790
- node(id: $id) {
1791
- ...on Document {
1792
- _values
1793
- _internalSys: _sys {
1794
- path
1795
- relativePath
1796
- collection {
1797
- name
1798
- }
1799
- }
1800
- }
1801
- }
1802
- }
1803
- `, { variables: { id: event.value } });
1804
- form = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
1805
- }
1806
- }
1807
- dispatch({
1808
- type: "onFieldChange",
1809
- value: {
1810
- event: {
1811
- ...event,
1812
- mutationType: { type: "referenceChange" }
1813
- },
1814
- form
1815
- }
1816
- });
1817
- } else {
1818
- dispatch({ type: "onFieldChange", value: { event } });
1819
- }
1820
- });
1821
- dispatch({ type: "done" });
1822
- }
1823
- }, [state.status]);
1824
- React.useEffect(() => {
1825
- state.changeSets.forEach((changeSet) => {
1826
- if (changeSet.mutationType.type === "reset") {
1827
- const form = cms.forms.find(changeSet.formId);
1828
- resolveSubFields({
1829
- formNode: changeSet.formNode,
1830
- form,
1831
- loc: []
1832
- }).then((res) => {
1833
- dispatch({
1834
- type: "setIn",
1835
- value: {
1836
- value: res,
1837
- path: changeSet.path
1838
- }
1839
- });
1840
- });
1841
- return;
1842
- } else if (changeSet.mutationType.type === "insert") {
1843
- if (changeSet.fieldDefinition.type === "object") {
1844
- const fieldName = changeSet.fieldDefinition.list ? `${changeSet.name}.[]` : changeSet.name;
1845
- const { fields, __typename } = getSubFields(changeSet);
1846
- resolveSubFields({
1847
- formNode: changeSet.formNode,
1848
- prefix: replaceRealNum(fieldName),
1849
- loc: [...stripIndices(changeSet.path), 0],
1850
- form: {
1851
- fields,
1852
- values: changeSet.value[0]
1853
- }
1854
- }).then((res) => {
1855
- const extra = {};
1856
- if (__typename) {
1857
- extra["__typename"] = __typename;
1858
- }
1859
- dispatch({
1860
- type: "setIn",
1861
- value: {
1862
- displaceIndex: true,
1863
- ...changeSet,
1864
- value: {
1865
- ...res,
1866
- ...extra
1867
- }
1868
- }
1869
- });
1870
- });
1871
- } else {
1872
- dispatch({
1873
- type: "setIn",
1874
- value: {
1875
- displaceIndex: true,
1876
- ...changeSet,
1877
- value: changeSet.value[0]
1878
- }
1879
- });
1880
- }
1881
- } else {
1882
- if (changeSet.mutationType.type === "referenceChange") {
1883
- const { formNode } = changeSet;
1884
- const blueprint = getFormNodeBlueprint(formNode, state);
1885
- if (!changeSet.value) {
1886
- dispatch({
1887
- type: "setIn",
1888
- value: {
1889
- ...changeSet,
1890
- value: null
1891
- }
1892
- });
1893
- } else {
1894
- cms.api.tina.request(`
1895
- query Node($id: String!) {
1896
- node(id: $id) {
1897
- ${G.print(blueprint.selection)}
1898
- }
1899
- }
1900
- `, { variables: { id: changeSet.value } }).then(async (res) => {
1901
- const form = state.documentForms.find((documentForm) => documentForm.id === formNode.documentFormId);
1902
- const data = await resolveSubFields({
1903
- formNode,
1904
- form,
1905
- loc: formNode.location
1906
- });
1907
- dispatch({
1908
- type: "setIn",
1909
- value: {
1910
- ...changeSet,
1911
- value: {
1912
- ...res.node,
1913
- ...data
1914
- }
1915
- }
1916
- });
1917
- }).catch((e) => {
1918
- cms.alerts.error(`Unexpected error fetching reference.`);
1919
- console.log(e);
1920
- });
1921
- }
1922
- } else {
1923
- dispatch({ type: "setIn", value: changeSet });
1924
- }
1925
- }
1926
- });
1927
- }, [JSON.stringify(state.changeSets)]);
1928
- React.useEffect(() => {
1929
- formIds.current = state.documentForms.map((df) => df.id);
1930
- }, [state.documentForms.length]);
1931
- React.useEffect(() => {
1932
- return () => {
1933
- formIds.current.forEach((formId) => {
1934
- const form = cms.forms.find(formId);
1935
- if (form) {
1936
- cms.plugins.remove(form);
25
+ let authTab;
26
+ window.addEventListener("message", function(e) {
27
+ if (e.data.source === TINA_LOGIN_EVENT) {
28
+ if (authTab) {
29
+ authTab.close();
1937
30
  }
1938
- });
1939
- };
1940
- }, []);
1941
- const resolveSubFields = React.useCallback(async (args) => {
1942
- const { form, formNode, prefix, loc } = args;
1943
- const data = {};
1944
- await sequential(form.fields, async (field) => {
1945
- const value = form.values[field.name];
1946
- const blueprint = getFormNodeBlueprint(formNode, state);
1947
- const { matchName, fieldName } = getMatchName({
1948
- field,
1949
- prefix,
1950
- blueprint
1951
- });
1952
- const fieldBlueprints = blueprint.fields.filter((fieldBlueprint) => {
1953
- return matchName === getBlueprintNamePath(fieldBlueprint);
1954
- }).filter((fbp) => filterFieldBlueprintsByParentTypename(fbp, field.parentTypename));
1955
- switch (field.type) {
1956
- case "object":
1957
- if (field.templates) {
1958
- if (field.list) {
1959
- await sequential(fieldBlueprints, async (fieldBlueprint) => {
1960
- const keyName = getFieldNameOrAlias(fieldBlueprint);
1961
- if (!value) {
1962
- data[keyName] = null;
1963
- return true;
1964
- }
1965
- if (!Array.isArray(value)) {
1966
- throw new Error(`Expected value for object list field to be an array`);
1967
- }
1968
- data[keyName] = await sequential(value, async (item, index) => {
1969
- const template = field.templates[item._template];
1970
- return {
1971
- ...await resolveSubFields({
1972
- formNode,
1973
- form: { fields: template.fields, values: item },
1974
- prefix: prefix ? [prefix, fieldName].join(".") : fieldName,
1975
- loc: [...loc, index]
1976
- }),
1977
- __typename: field.typeMap[item._template]
1978
- };
1979
- });
1980
- });
1981
- } else {
1982
- throw new Error("blocks without list true is not yet supported");
1983
- }
1984
- } else {
1985
- if (field.list) {
1986
- await sequential(fieldBlueprints, async (fieldBlueprint) => {
1987
- const keyName = getFieldNameOrAlias(fieldBlueprint);
1988
- if (!value) {
1989
- data[keyName] = null;
1990
- return true;
1991
- }
1992
- if (!Array.isArray(value)) {
1993
- throw new Error(`Expected value for object list field to be an array`);
1994
- }
1995
- data[keyName] = await sequential(value, async (item, index) => {
1996
- return resolveSubFields({
1997
- formNode,
1998
- form: { fields: field.fields, values: item },
1999
- prefix: [prefix, fieldName].join("."),
2000
- loc: [...loc, index]
2001
- });
2002
- });
2003
- return true;
2004
- });
2005
- } else {
2006
- await sequential(fieldBlueprints, async (fieldBlueprint) => {
2007
- const keyName = getFieldNameOrAlias(fieldBlueprint);
2008
- if (!value) {
2009
- data[keyName] = null;
2010
- return true;
2011
- }
2012
- data[keyName] = await resolveSubFields({
2013
- formNode,
2014
- form: { fields: field.fields, values: value },
2015
- prefix: [prefix, fieldName].join("."),
2016
- loc
2017
- });
2018
- return true;
2019
- });
2020
- }
2021
- }
2022
- break;
2023
- case "reference":
2024
- let form2;
2025
- if (typeof value === "string") {
2026
- const existingForm = cms.forms.find(value);
2027
- if (existingForm) {
2028
- form2 = existingForm;
2029
- } else {
2030
- const formInfo = await cms.api.tina.request(`#graphql
2031
- query Node($id: String!) {
2032
- node(id: $id) {
2033
- ...on Document {
2034
- _values
2035
- _internalSys: _sys {
2036
- path
2037
- relativePath
2038
- collection {
2039
- name
2040
- }
2041
- }
2042
- }
2043
- }
2044
- }
2045
- `, { variables: { id: value } });
2046
- form2 = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
2047
- }
2048
- }
2049
- await sequential(fieldBlueprints, async (fieldBlueprint) => {
2050
- const keyName = getFieldNameOrAlias(fieldBlueprint);
2051
- if (!value) {
2052
- data[keyName] = null;
2053
- return true;
2054
- }
2055
- const documentBlueprint = state.blueprints.find((dp) => getBlueprintNamePath(dp) === matchName);
2056
- const location = [...formNode.location];
2057
- if (loc) {
2058
- loc.forEach((item) => location.push(item));
2059
- }
2060
- const subDocumentFormNode = buildFormNode(documentBlueprint, form2, location);
2061
- dispatch({
2062
- type: "addOrReplaceDocumentFormNode",
2063
- value: {
2064
- formNode: subDocumentFormNode,
2065
- documentForm: form2
2066
- }
2067
- });
2068
- const res = await cms.api.tina.request(`
2069
- query Node($id: String!) {
2070
- node(id: $id) {
2071
- ${G.print(documentBlueprint.selection)}
2072
- }
2073
- }
2074
- `, { variables: { id: value } });
2075
- data[keyName] = {
2076
- ...res.node,
2077
- ...await resolveSubFields({
2078
- formNode: subDocumentFormNode,
2079
- form: form2,
2080
- loc: location
2081
- })
2082
- };
2083
- });
2084
- break;
2085
- default:
2086
- fieldBlueprints.forEach((fieldBlueprint) => {
2087
- const keyName = getFieldNameOrAlias(fieldBlueprint);
2088
- if (!value) {
2089
- data[keyName] = null;
2090
- } else {
2091
- data[keyName] = value;
2092
- }
2093
- });
2094
- break;
31
+ resolve({
32
+ id_token: e.data.id_token,
33
+ access_token: e.data.access_token,
34
+ refresh_token: e.data.refresh_token
35
+ });
2095
36
  }
2096
- return true;
2097
37
  });
2098
- return data;
2099
- }, [cms, JSON.stringify(state), dispatch]);
2100
- return {
2101
- ...state,
2102
- queryString: G.print(state.query)
2103
- };
2104
- };
2105
- const buildFormNode = (documentBlueprint, form, location) => {
2106
- return {
2107
- documentBlueprintId: documentBlueprint.id,
2108
- documentFormId: form.id,
2109
- location
2110
- };
38
+ const origin = `${window.location.protocol}//${window.location.host}`;
39
+ authTab = popupWindow(`${frontendUrl}/signin?clientId=${clientId}&origin=${origin}`, "_blank", window, 1e3, 700);
40
+ });
2111
41
  };
2112
42
  const captureBranchName = /^refs\/heads\/(.*)/;
2113
43
  const parseRefForBranchName = (ref) => {
2114
44
  const matches = ref.match(captureBranchName);
2115
45
  return matches[1];
2116
46
  };
47
+ const ListBranchResponse = z.object({
48
+ name: z.string(),
49
+ protected: z.boolean(),
50
+ commit: z.object({ sha: z.string(), url: z.string() })
51
+ }).array();
52
+ const IndexStatusResponse = z.object({
53
+ status: z.union([
54
+ z.literal("complete"),
55
+ z.literal("unknown"),
56
+ z.literal("failed"),
57
+ z.literal("inprogress")
58
+ ]).optional(),
59
+ timestamp: z.number().optional()
60
+ });
61
+ async function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
62
+ const endTime = new Date().getTime() + pollTimeout;
63
+ const checkCondition = (resolve, reject) => {
64
+ Promise.resolve(fn()).then((result) => {
65
+ const now = new Date().getTime();
66
+ if (result.done) {
67
+ resolve(result.data);
68
+ } else if (now < endTime) {
69
+ setTimeout(checkCondition, pollInterval, resolve, reject);
70
+ } else {
71
+ reject(new Error("AsyncPoller: reached timeout"));
72
+ }
73
+ }).catch((err) => {
74
+ reject(err);
75
+ });
76
+ };
77
+ return new Promise(checkCondition);
78
+ }
2117
79
  class Client {
2118
80
  constructor({ tokenStorage = "MEMORY", ...options }) {
2119
81
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P;
@@ -2250,24 +212,6 @@ mutation addPendingDocumentMutation(
2250
212
  this.contentApiBase = ((_d = this.options.tinaioConfig) == null ? void 0 : _d.contentApiUrlOverride) || `https://content.tinajs.io`;
2251
213
  this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
2252
214
  }
2253
- async requestWithForm(query, {
2254
- variables,
2255
- useUnstableFormify
2256
- }) {
2257
- const schema = await this.getSchema();
2258
- let formifiedQuery;
2259
- if (useUnstableFormify) {
2260
- const res = await formify({
2261
- schema,
2262
- query: print(query(gql$1)),
2263
- getOptimizedQuery: this.getOptimizedQuery
2264
- });
2265
- formifiedQuery = res.formifiedQuery;
2266
- } else {
2267
- formifiedQuery = formify$1(query(gql$1), schema);
2268
- }
2269
- return this.request(print(formifiedQuery), { variables });
2270
- }
2271
215
  async request(query, { variables }) {
2272
216
  const res = await fetch(this.contentApiUrl, {
2273
217
  method: "POST",
@@ -2431,12 +375,64 @@ mutation addPendingDocumentMutation(
2431
375
  return null;
2432
376
  }
2433
377
  }
378
+ async waitForIndexStatus({ ref }) {
379
+ try {
380
+ const result = await asyncPoll(async () => {
381
+ try {
382
+ const result2 = await this.getIndexStatus({ ref });
383
+ if (!(result2.status === "inprogress" || result2.status === "unknown")) {
384
+ return Promise.resolve({
385
+ done: true,
386
+ data: result2
387
+ });
388
+ } else {
389
+ return Promise.resolve({
390
+ done: false
391
+ });
392
+ }
393
+ } catch (err) {
394
+ return Promise.reject(err);
395
+ }
396
+ }, 5e3, 9e5);
397
+ return result;
398
+ } catch (error) {
399
+ if (error.message === "AsyncPoller: reached timeout") {
400
+ console.warn(error);
401
+ return {
402
+ status: "timeout"
403
+ };
404
+ }
405
+ throw error;
406
+ }
407
+ }
408
+ async getIndexStatus({ ref }) {
409
+ const url = `${this.contentApiBase}/db/${this.clientId}/status/${ref}`;
410
+ const res = await this.fetchWithToken(url);
411
+ const result = await res.json();
412
+ const parsedResult = IndexStatusResponse.parse(result);
413
+ return parsedResult;
414
+ }
2434
415
  async listBranches() {
2435
- const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2436
- const res = await this.fetchWithToken(url, {
2437
- method: "GET"
2438
- });
2439
- return res.json();
416
+ try {
417
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
418
+ const res = await this.fetchWithToken(url, {
419
+ method: "GET"
420
+ });
421
+ const branches = await res.json();
422
+ const parsedBranches = ListBranchResponse.parse(branches);
423
+ const indexStatusPromises = parsedBranches.map(async (branch) => {
424
+ const indexStatus2 = await this.getIndexStatus({ ref: branch.name });
425
+ return {
426
+ ...branch,
427
+ indexStatus: indexStatus2
428
+ };
429
+ });
430
+ const indexStatus = await Promise.all(indexStatusPromises);
431
+ return indexStatus;
432
+ } catch (error) {
433
+ console.error("There was an error listing branches.", error);
434
+ throw error;
435
+ }
2440
436
  }
2441
437
  async createBranch({ baseBranch, branchName }) {
2442
438
  const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
@@ -2509,6 +505,7 @@ const AsyncButton = ({ name, primary, action }) => {
2509
505
  }
2510
506
  }, [action, setSubmitting]);
2511
507
  return /* @__PURE__ */ React.createElement(Button, {
508
+ "data-test": name.replace(/\s/g, "-").toLowerCase(),
2512
509
  variant: primary ? "primary" : "secondary",
2513
510
  onClick,
2514
511
  busy: submitting,
@@ -2530,6 +527,39 @@ const useTinaAuthRedirect = () => {
2530
527
  localStorage[TINA_AUTH_CONFIG] = JSON.stringify(config);
2531
528
  }, []);
2532
529
  };
530
+ const createClient = ({
531
+ clientId,
532
+ isLocalClient = true,
533
+ branch,
534
+ tinaioConfig,
535
+ schema,
536
+ apiUrl
537
+ }) => {
538
+ return isLocalClient ? new LocalClient({ customContentApiUrl: apiUrl, schema }) : new Client({
539
+ clientId: clientId || "",
540
+ branch: branch || "main",
541
+ tokenStorage: "LOCAL_STORAGE",
542
+ tinaioConfig,
543
+ schema
544
+ });
545
+ };
546
+ function assertShape(value, yupSchema, errorMessage) {
547
+ const shape = yupSchema(yup);
548
+ try {
549
+ shape.validateSync(value);
550
+ } catch (e) {
551
+ const message = errorMessage || `Failed to assertShape - ${e.message}`;
552
+ throw new Error(message);
553
+ }
554
+ }
555
+ function safeAssertShape(value, yupSchema) {
556
+ try {
557
+ assertShape(value, yupSchema);
558
+ return true;
559
+ } catch (e) {
560
+ return false;
561
+ }
562
+ }
2533
563
  class TinaAdminApi {
2534
564
  constructor(cms) {
2535
565
  this.api = cms.api.tina;
@@ -2538,6 +568,17 @@ class TinaAdminApi {
2538
568
  async isAuthenticated() {
2539
569
  return await this.api.isAuthenticated();
2540
570
  }
571
+ async checkGraphqlSchema({ localSchema }) {
572
+ const schemaFromCloud = await this.api.getSchema();
573
+ const schema1 = schemaFromCloud;
574
+ const schema2 = buildSchema(print(localSchema));
575
+ const diffOutput = await diff(schema1, schema2);
576
+ if (diffOutput.length > 0) {
577
+ return false;
578
+ } else {
579
+ return true;
580
+ }
581
+ }
2541
582
  fetchCollections() {
2542
583
  return this.schema.getCollections();
2543
584
  }
@@ -3273,6 +1314,15 @@ var styles = `.tina-tailwind {
3273
1314
  margin-left: auto;
3274
1315
  margin-right: auto;
3275
1316
  }
1317
+ .tina-tailwind .mb-6 {
1318
+ margin-bottom: 24px;
1319
+ }
1320
+ .tina-tailwind .mr-1 {
1321
+ margin-right: 4px;
1322
+ }
1323
+ .tina-tailwind .mb-8 {
1324
+ margin-bottom: 32px;
1325
+ }
3276
1326
  .tina-tailwind .-ml-px {
3277
1327
  margin-left: -1px;
3278
1328
  }
@@ -3306,18 +1356,12 @@ var styles = `.tina-tailwind {
3306
1356
  .tina-tailwind .mr-1\\.5 {
3307
1357
  margin-right: 6px;
3308
1358
  }
3309
- .tina-tailwind .mr-1 {
3310
- margin-right: 4px;
3311
- }
3312
1359
  .tina-tailwind .block {
3313
1360
  display: block;
3314
1361
  }
3315
1362
  .tina-tailwind .inline-block {
3316
1363
  display: inline-block;
3317
1364
  }
3318
- .tina-tailwind .inline {
3319
- display: inline;
3320
- }
3321
1365
  .tina-tailwind .flex {
3322
1366
  display: flex;
3323
1367
  }
@@ -3360,6 +1404,12 @@ var styles = `.tina-tailwind {
3360
1404
  .tina-tailwind .w-10 {
3361
1405
  width: 40px;
3362
1406
  }
1407
+ .tina-tailwind .w-12 {
1408
+ width: 48px;
1409
+ }
1410
+ .tina-tailwind .w-7 {
1411
+ width: 28px;
1412
+ }
3363
1413
  .tina-tailwind .w-auto {
3364
1414
  width: auto;
3365
1415
  }
@@ -3555,6 +1605,10 @@ var styles = `.tina-tailwind {
3555
1605
  --tw-bg-opacity: 1;
3556
1606
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
3557
1607
  }
1608
+ .tina-tailwind .bg-gray-100 {
1609
+ --tw-bg-opacity: 1;
1610
+ background-color: rgb(237 236 243 / var(--tw-bg-opacity));
1611
+ }
3558
1612
  .tina-tailwind .bg-gray-50 {
3559
1613
  --tw-bg-opacity: 1;
3560
1614
  background-color: rgb(246 246 249 / var(--tw-bg-opacity));
@@ -3597,6 +1651,9 @@ var styles = `.tina-tailwind {
3597
1651
  .tina-tailwind .to-black {
3598
1652
  --tw-gradient-to: #000;
3599
1653
  }
1654
+ .tina-tailwind .fill-current {
1655
+ fill: currentColor;
1656
+ }
3600
1657
  .tina-tailwind .px-4 {
3601
1658
  padding-left: 16px;
3602
1659
  padding-right: 16px;
@@ -3691,14 +1748,18 @@ var styles = `.tina-tailwind {
3691
1748
  font-size: 16px;
3692
1749
  line-height: 1.5;
3693
1750
  }
3694
- .tina-tailwind .text-sm {
3695
- font-size: 14px;
3696
- line-height: 1.43;
1751
+ .tina-tailwind .text-4xl {
1752
+ font-size: 36px;
1753
+ line-height: 1.1;
3697
1754
  }
3698
1755
  .tina-tailwind .text-xl {
3699
1756
  font-size: 20px;
3700
1757
  line-height: 1.4;
3701
1758
  }
1759
+ .tina-tailwind .text-sm {
1760
+ font-size: 14px;
1761
+ line-height: 1.43;
1762
+ }
3702
1763
  .tina-tailwind .text-md {
3703
1764
  font-size: 16px;
3704
1765
  line-height: 1.5;
@@ -3739,6 +1800,14 @@ var styles = `.tina-tailwind {
3739
1800
  --tw-text-opacity: 1;
3740
1801
  color: rgb(67 62 82 / var(--tw-text-opacity));
3741
1802
  }
1803
+ .tina-tailwind .text-red-500 {
1804
+ --tw-text-opacity: 1;
1805
+ color: rgb(239 68 68 / var(--tw-text-opacity));
1806
+ }
1807
+ .tina-tailwind .text-red-400 {
1808
+ --tw-text-opacity: 1;
1809
+ color: rgb(248 113 113 / var(--tw-text-opacity));
1810
+ }
3742
1811
  .tina-tailwind .text-blue-600 {
3743
1812
  --tw-text-opacity: 1;
3744
1813
  color: rgb(5 116 228 / var(--tw-text-opacity));
@@ -3774,13 +1843,12 @@ var styles = `.tina-tailwind {
3774
1843
  --tw-text-opacity: 1;
3775
1844
  color: rgb(37 35 54 / var(--tw-text-opacity));
3776
1845
  }
3777
- .tina-tailwind .text-red-500 {
3778
- --tw-text-opacity: 1;
3779
- color: rgb(239 68 68 / var(--tw-text-opacity));
3780
- }
3781
1846
  .tina-tailwind .underline {
3782
1847
  text-decoration-line: underline;
3783
1848
  }
1849
+ .tina-tailwind .opacity-70 {
1850
+ opacity: .7;
1851
+ }
3784
1852
  .tina-tailwind .opacity-100 {
3785
1853
  opacity: 1;
3786
1854
  }
@@ -3799,9 +1867,6 @@ var styles = `.tina-tailwind {
3799
1867
  .tina-tailwind .opacity-50 {
3800
1868
  opacity: .5;
3801
1869
  }
3802
- .tina-tailwind .opacity-70 {
3803
- opacity: .7;
3804
- }
3805
1870
  .tina-tailwind .shadow-lg {
3806
1871
  --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
3807
1872
  --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
@@ -4126,42 +2191,6 @@ const useDocumentCreatorPlugin = (args) => {
4126
2191
  };
4127
2192
  }, [plugin]);
4128
2193
  };
4129
- function useTina({
4130
- query,
4131
- variables,
4132
- data
4133
- }) {
4134
- React.useEffect(() => {
4135
- console.warn(`
4136
- "useTina" from 'tinacms/dist/edit-state' is now deprecated
4137
- * Use "import { useTina } from 'tinacms/dist/react" instead.
4138
- * See https://tina.io/blog/upgrading-to-iframe/ for full migration details
4139
- `);
4140
- }, []);
4141
- const {
4142
- setRequest,
4143
- state,
4144
- isDummyContainer,
4145
- isLoading: contextLoading
4146
- } = React.useContext(TinaDataContext);
4147
- const [waitForContextRerender, setWaitForContextRerender] = useState(!isDummyContainer);
4148
- const isLoading = contextLoading || waitForContextRerender;
4149
- React.useEffect(() => {
4150
- setRequest({ query, variables });
4151
- }, [JSON.stringify(variables), query]);
4152
- useEffect(() => {
4153
- if (!isDummyContainer) {
4154
- setTimeout(() => setWaitForContextRerender(false), 0);
4155
- }
4156
- return () => {
4157
- setRequest(void 0);
4158
- };
4159
- }, [isDummyContainer]);
4160
- return {
4161
- data: isDummyContainer || isLoading ? data : state.payload,
4162
- isLoading
4163
- };
4164
- }
4165
2194
  const errorButtonStyles = {
4166
2195
  background: "#eb6337",
4167
2196
  padding: "12px 18px",
@@ -4249,12 +2278,6 @@ const TinaCMSProvider2 = ({
4249
2278
  ...props
4250
2279
  }) => {
4251
2280
  var _a, _b, _c, _d, _e;
4252
- React.useEffect(() => {
4253
- console.warn(`
4254
- * Tina no longer requires wrapping your site in the TinaProvider
4255
- * See https://tina.io/blog/upgrading-to-iframe/ for full migration details
4256
- `);
4257
- }, []);
4258
2281
  if (props == null ? void 0 : props.apiURL) {
4259
2282
  console.warn("The apiURL prop is deprecated. Please see https://tina.io/blog/tina-v-0.68.14 for information on how to upgrade to the new API");
4260
2283
  }
@@ -4280,84 +2303,7 @@ const TinaCMSProvider2 = ({
4280
2303
  mediaStore: props.mediaStore,
4281
2304
  apiUrl: apiURL,
4282
2305
  schema: { ...schema, config: { ...schema.config, ...props } }
4283
- }, /* @__PURE__ */ React.createElement("style", null, styles), /* @__PURE__ */ React.createElement(ErrorBoundary, null, /* @__PURE__ */ React.createElement(DocumentCreator, {
4284
- documentCreatorCallback
4285
- }), /* @__PURE__ */ React.createElement(TinaDataProvider, {
4286
- formifyCallback
4287
- }, typeof props.children == "function" ? /* @__PURE__ */ React.createElement(TinaQuery, {
4288
- ...props,
4289
- variables: props.variables,
4290
- data: props.data,
4291
- query,
4292
- formifyCallback,
4293
- children: props.children
4294
- }) : props.children))));
4295
- };
4296
- const DocumentCreator = ({
4297
- documentCreatorCallback
4298
- }) => {
4299
- useDocumentCreatorPlugin(documentCreatorCallback);
4300
- return null;
4301
- };
4302
- const TinaQuery = (props) => {
4303
- return /* @__PURE__ */ React.createElement(TinaQueryInner, {
4304
- key: `rootQuery-${props.query}`,
4305
- ...props
4306
- });
4307
- };
4308
- const TinaQueryInner = ({ children, ...props }) => {
4309
- const { data: liveData, isLoading } = useTina({
4310
- query: props.query,
4311
- variables: props.variables,
4312
- data: props.data
4313
- });
4314
- return /* @__PURE__ */ React.createElement(React.Fragment, null, children(isLoading || !props.query ? props : { ...props, data: liveData }));
4315
- };
4316
- const TinaDataProvider = ({
4317
- children,
4318
- formifyCallback
4319
- }) => {
4320
- const [request, setRequest] = useState();
4321
- const [state, setState] = React.useState({
4322
- payload: void 0,
4323
- isLoading: true
4324
- });
4325
- return /* @__PURE__ */ React.createElement(TinaDataContext.Provider, {
4326
- value: {
4327
- setRequest,
4328
- isLoading: state.isLoading,
4329
- state: { payload: state.payload }
4330
- }
4331
- }, /* @__PURE__ */ React.createElement(FormRegistrar, {
4332
- key: request == null ? void 0 : request.query,
4333
- request,
4334
- formifyCallback,
4335
- onPayloadStateChange: setState
4336
- }), children);
4337
- };
4338
- const FormRegistrar = ({
4339
- request,
4340
- formifyCallback,
4341
- onPayloadStateChange
4342
- }) => {
4343
- const cms = useCMS();
4344
- const { setFormsRegistering } = React.useContext(EditContext);
4345
- const [payload, isLoading] = useGraphqlForms({
4346
- query: request == null ? void 0 : request.query,
4347
- variables: request == null ? void 0 : request.variables,
4348
- formify: (args) => {
4349
- if (formifyCallback) {
4350
- return formifyCallback(args, cms);
4351
- } else {
4352
- return args.createForm(args.formConfig);
4353
- }
4354
- }
4355
- });
4356
- React.useEffect(() => {
4357
- onPayloadStateChange({ payload, isLoading });
4358
- setFormsRegistering && setFormsRegistering(isLoading);
4359
- }, [JSON.stringify(payload), isLoading]);
4360
- return isLoading ? /* @__PURE__ */ React.createElement(Loader, null, /* @__PURE__ */ React.createElement(React.Fragment, null)) : null;
2306
+ }, /* @__PURE__ */ React.createElement("style", null, styles), /* @__PURE__ */ React.createElement(ErrorBoundary, null, props.children)));
4361
2307
  };
4362
2308
  const Loader = (props) => {
4363
2309
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
@@ -4551,10 +2497,10 @@ var __rest = globalThis && globalThis.__rest || function(s, e) {
4551
2497
  return t;
4552
2498
  };
4553
2499
  function Tree2Element(tree) {
4554
- return tree && tree.map(function(node2, i) {
4555
- return React.createElement(node2.tag, __assign({
2500
+ return tree && tree.map(function(node, i) {
2501
+ return React.createElement(node.tag, __assign({
4556
2502
  key: i
4557
- }, node2.attr), Tree2Element(node2.child));
2503
+ }, node.attr), Tree2Element(node.child));
4558
2504
  });
4559
2505
  }
4560
2506
  function GenIcon(data) {
@@ -4604,6 +2550,9 @@ function IoMdClose(props) {
4604
2550
  function BiEdit(props) {
4605
2551
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m7 17.013 4.413-.015 9.632-9.54c.378-.378.586-.88.586-1.414s-.208-1.036-.586-1.414l-1.586-1.586c-.756-.756-2.075-.752-2.825-.003L7 12.583v4.43zM18.045 4.458l1.589 1.583-1.597 1.582-1.586-1.585 1.594-1.58zM9 13.417l6.03-5.973 1.586 1.586-6.029 5.971L9 15.006v-1.589z" } }, { "tag": "path", "attr": { "d": "M5 21h14c1.103 0 2-.897 2-2v-8.668l-2 2V19H8.158c-.026 0-.053.01-.079.01-.033 0-.066-.009-.1-.01H5V5h6.847l2-2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2z" } }] })(props);
4606
2552
  }
2553
+ function BiError(props) {
2554
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M11.001 10h2v5h-2zM11 16h2v2h-2z" } }, { "tag": "path", "attr": { "d": "M13.768 4.2C13.42 3.545 12.742 3.138 12 3.138s-1.42.407-1.768 1.063L2.894 18.064a1.986 1.986 0 0 0 .054 1.968A1.984 1.984 0 0 0 4.661 21h14.678c.708 0 1.349-.362 1.714-.968a1.989 1.989 0 0 0 .054-1.968L13.768 4.2zM4.661 19 12 5.137 19.344 19H4.661z" } }] })(props);
2555
+ }
4607
2556
  function BiLogIn(props) {
4608
2557
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 16 5-4-5-4v3H4v2h9z" } }, { "tag": "path", "attr": { "d": "M20 3h-9c-1.103 0-2 .897-2 2v4h2V5h9v14h-9v-4H9v4c0 1.103.897 2 2 2h9c1.103 0 2-.897 2-2V5c0-1.103-.897-2-2-2z" } }] })(props);
4609
2558
  }
@@ -4622,6 +2571,9 @@ function BiRename(props) {
4622
2571
  function BiSearch(props) {
4623
2572
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M10 18a7.952 7.952 0 0 0 4.897-1.688l4.396 4.396 1.414-1.414-4.396-4.396A7.952 7.952 0 0 0 18 10c0-4.411-3.589-8-8-8s-8 3.589-8 8 3.589 8 8 8zm0-14c3.309 0 6 2.691 6 6s-2.691 6-6 6-6-2.691-6-6 2.691-6 6-6z" } }] })(props);
4624
2573
  }
2574
+ function BiSync(props) {
2575
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "m13 7.101.01.001a4.978 4.978 0 0 1 2.526 1.362 5.005 5.005 0 0 1 1.363 2.528 5.061 5.061 0 0 1-.001 2.016 4.976 4.976 0 0 1-1.363 2.527l1.414 1.414a7.014 7.014 0 0 0 1.908-3.54 6.98 6.98 0 0 0 0-2.819 6.957 6.957 0 0 0-1.907-3.539 6.97 6.97 0 0 0-2.223-1.5 6.921 6.921 0 0 0-1.315-.408c-.137-.028-.275-.043-.412-.063V2L9 6l4 4V7.101zm-7.45 7.623c.174.412.392.812.646 1.19.249.37.537.718.854 1.034a7.036 7.036 0 0 0 2.224 1.501c.425.18.868.317 1.315.408.167.034.338.056.508.078v2.944l4-4-4-4v3.03c-.035-.006-.072-.003-.107-.011a4.978 4.978 0 0 1-2.526-1.362 4.994 4.994 0 0 1 .001-7.071L7.051 7.05a7.01 7.01 0 0 0-1.5 2.224A6.974 6.974 0 0 0 5 12a6.997 6.997 0 0 0 .55 2.724z" } }] })(props);
2576
+ }
4625
2577
  function BiTrash(props) {
4626
2578
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "d": "M5 20a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8h2V6h-4V4a2 2 0 0 0-2-2H9a2 2 0 0 0-2 2v2H3v2h2zM9 4h6v2H9zM8 8h9v12H7V8z" } }, { "tag": "path", "attr": { "d": "M9 10h2v8H9zm4 0h2v8h-2z" } }] })(props);
4627
2579
  }
@@ -5033,6 +2985,25 @@ const LoadingPage = () => /* @__PURE__ */ React.createElement(React.Fragment, nu
5033
2985
  fontWeight: "normal"
5034
2986
  }
5035
2987
  }, "Please wait, Tina is loading data..."))));
2988
+ const FullscreenError = ({
2989
+ title = "Error",
2990
+ errorMessage = "It looks like something went wrong."
2991
+ }) => {
2992
+ return /* @__PURE__ */ React.createElement("div", {
2993
+ className: "flex flex-col justify-center items-center h-screen bg-gray-100"
2994
+ }, /* @__PURE__ */ React.createElement("div", {
2995
+ className: "text-red-500 text-4xl mb-6 flex items-center"
2996
+ }, /* @__PURE__ */ React.createElement(BiError, {
2997
+ className: "w-12 h-auto fill-current text-red-400 opacity-70 mr-1"
2998
+ }), " ", title), /* @__PURE__ */ React.createElement("p", {
2999
+ className: "text-gray-700 text-xl mb-8"
3000
+ }, errorMessage), /* @__PURE__ */ React.createElement(Button, {
3001
+ variant: "danger",
3002
+ onClick: () => window.location.reload()
3003
+ }, /* @__PURE__ */ React.createElement(BiSync, {
3004
+ className: "w-7 h-auto fill-current opacity-70 mr-1"
3005
+ }), " Reload"));
3006
+ };
5036
3007
  const useGetCollection = (cms, collectionName, includeDocuments = true, after = "", sortKey, filterArgs) => {
5037
3008
  const api = new TinaAdminApi(cms);
5038
3009
  const schema = cms.api.tina.schema;
@@ -5076,7 +3047,7 @@ const GetCollection = ({
5076
3047
  }) => {
5077
3048
  const { collection, loading, error, reFetchCollection, collectionExtra } = useGetCollection(cms, collectionName, includeDocuments, startCursor || "", sortKey, filterArgs) || {};
5078
3049
  if (error) {
5079
- return null;
3050
+ return /* @__PURE__ */ React.createElement(FullscreenError, null);
5080
3051
  }
5081
3052
  if (loading) {
5082
3053
  return /* @__PURE__ */ React.createElement(LoadingPage, null);
@@ -5178,7 +3149,7 @@ const CollectionListPage = () => {
5178
3149
  }));
5179
3150
  }, [collectionName]);
5180
3151
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => {
5181
- return /* @__PURE__ */ React.createElement(GetCollection, {
3152
+ return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(GetCollection, {
5182
3153
  cms,
5183
3154
  collectionName,
5184
3155
  includeDocuments: true,
@@ -5212,7 +3183,7 @@ const CollectionListPage = () => {
5212
3183
  const collectionDefinition = cms.api.tina.schema.getCollection(collection.name);
5213
3184
  const allowCreate = (_e = (_d = (_c = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _c.allowedActions) == null ? void 0 : _d.create) != null ? _e : true;
5214
3185
  const allowDelete = (_h = (_g = (_f = collectionDefinition == null ? void 0 : collectionDefinition.ui) == null ? void 0 : _f.allowedActions) == null ? void 0 : _g.delete) != null ? _h : true;
5215
- return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(React.Fragment, null, deleteModalOpen && /* @__PURE__ */ React.createElement(DeleteModal, {
3186
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, deleteModalOpen && /* @__PURE__ */ React.createElement(DeleteModal, {
5216
3187
  filename: vars.relativePath,
5217
3188
  deleteFunc: async () => {
5218
3189
  try {
@@ -5321,7 +3292,7 @@ const CollectionListPage = () => {
5321
3292
  value: ""
5322
3293
  },
5323
3294
  ...filterFields.map((x) => ({
5324
- label: x.label || x.name,
3295
+ label: typeof x.label === "string" && x.label || x.name,
5325
3296
  value: x.name
5326
3297
  }))
5327
3298
  ],
@@ -5376,7 +3347,7 @@ const CollectionListPage = () => {
5376
3347
  onChange: (e) => {
5377
3348
  setVars((old) => ({
5378
3349
  ...old,
5379
- after: e.format(),
3350
+ after: typeof e.format === "function" ? e.format() : "",
5380
3351
  booleanEquals: null,
5381
3352
  startsWith: ""
5382
3353
  }));
@@ -5394,7 +3365,7 @@ const CollectionListPage = () => {
5394
3365
  onChange: (e) => {
5395
3366
  setVars((old) => ({
5396
3367
  ...old,
5397
- before: e.format(),
3368
+ before: typeof e.format === "function" ? e.format() : "",
5398
3369
  booleanEquals: null,
5399
3370
  startsWith: ""
5400
3371
  }));
@@ -5576,8 +3547,8 @@ const CollectionListPage = () => {
5576
3547
  setEndCursor(prev);
5577
3548
  }
5578
3549
  }
5579
- }))))));
5580
- });
3550
+ })))));
3551
+ }));
5581
3552
  });
5582
3553
  };
5583
3554
  const NoDocumentsPlaceholder = () => {
@@ -5636,6 +3607,42 @@ const RenameModal = ({
5636
3607
  function HiChevronRight(props) {
5637
3608
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 20 20", "fill": "currentColor" }, "child": [{ "tag": "path", "attr": { "fillRule": "evenodd", "d": "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", "clipRule": "evenodd" } }] })(props);
5638
3609
  }
3610
+ const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
3611
+ const { _collection, __typename, _template, ...rest } = document;
3612
+ const params = transformParams(rest);
3613
+ const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
3614
+ return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
3615
+ };
3616
+ const transformParams = (data) => {
3617
+ if (["string", "number", "boolean"].includes(typeof data)) {
3618
+ return data;
3619
+ }
3620
+ if (Array.isArray(data)) {
3621
+ return data.map((item) => transformParams(item));
3622
+ }
3623
+ try {
3624
+ assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
3625
+ const { _template, __typename, ...rest } = data;
3626
+ const nested = transformParams(rest);
3627
+ return { [_template]: nested };
3628
+ } catch (e) {
3629
+ if (e.message === "Failed to assertShape - _template is a required field") {
3630
+ if (!data) {
3631
+ return [];
3632
+ }
3633
+ const accum = {};
3634
+ Object.entries(data).map(([keyName, value]) => {
3635
+ accum[keyName] = transformParams(value);
3636
+ });
3637
+ return accum;
3638
+ } else {
3639
+ if (!data) {
3640
+ return [];
3641
+ }
3642
+ throw e;
3643
+ }
3644
+ }
3645
+ };
5639
3646
  function FaLock(props) {
5640
3647
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 448 512" }, "child": [{ "tag": "path", "attr": { "d": "M400 224h-24v-72C376 68.2 307.8 0 224 0S72 68.2 72 152v72H48c-26.5 0-48 21.5-48 48v192c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V272c0-26.5-21.5-48-48-48zm-104 0H152v-72c0-39.7 32.3-72 72-72s72 32.3 72 72v72z" } }] })(props);
5641
3648
  }
@@ -5717,7 +3724,7 @@ const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
5717
3724
  schema,
5718
3725
  template
5719
3726
  });
5720
- let slugFunction = (_b = (_a = template == null ? void 0 : template.ui) == null ? void 0 : _a.filename) == null ? void 0 : _b.slugify;
3727
+ let slugFunction = (_b = (_a = schemaCollection.ui) == null ? void 0 : _a.filename) == null ? void 0 : _b.slugify;
5721
3728
  if (!slugFunction) {
5722
3729
  const titleField = (_c = template == null ? void 0 : template.fields.find((x) => x.required && x.type === "string" && x.isTitle)) == null ? void 0 : _c.name;
5723
3730
  if (titleField) {
@@ -5750,11 +3757,11 @@ const RenderForm$1 = ({ cms, collection, templateName, mutationInfo }) => {
5750
3757
  component: slugFunction ? wrapFieldsWithMeta(({ field, input, meta }) => {
5751
3758
  var _a3, _b3;
5752
3759
  return /* @__PURE__ */ React.createElement(FilenameInput, {
5753
- readonly: (_b3 = (_a3 = template == null ? void 0 : template.ui) == null ? void 0 : _a3.filename) == null ? void 0 : _b3.readonly,
3760
+ readonly: (_b3 = (_a3 = schemaCollection == null ? void 0 : schemaCollection.ui) == null ? void 0 : _a3.filename) == null ? void 0 : _b3.readonly,
5754
3761
  ...input
5755
3762
  });
5756
3763
  }) : "text",
5757
- disabled: (_b2 = (_a2 = template == null ? void 0 : template.ui) == null ? void 0 : _a2.filename) == null ? void 0 : _b2.readonly,
3764
+ disabled: (_b2 = (_a2 = schemaCollection == null ? void 0 : schemaCollection.ui) == null ? void 0 : _a2.filename) == null ? void 0 : _b2.readonly,
5758
3765
  description: /* @__PURE__ */ React.createElement("span", null, "A unique filename for the content.", /* @__PURE__ */ React.createElement("br", null), "Examples: ", /* @__PURE__ */ React.createElement("code", null, "My_Document"), ", ", /* @__PURE__ */ React.createElement("code", null, "My_Document.en"), ",", " ", /* @__PURE__ */ React.createElement("code", null, "sub-folder/My_Document")),
5759
3766
  placeholder: `My_Document`,
5760
3767
  validate: (value, allValues, meta) => {
@@ -5848,7 +3855,7 @@ const GetDocument = ({
5848
3855
  }) => {
5849
3856
  const { document, loading, error } = useGetDocument(cms, collectionName, relativePath);
5850
3857
  if (error) {
5851
- return null;
3858
+ return /* @__PURE__ */ React.createElement(FullscreenError, null);
5852
3859
  }
5853
3860
  if (loading) {
5854
3861
  return /* @__PURE__ */ React.createElement(LoadingPage, null);
@@ -5884,7 +3891,7 @@ const CollectionUpdatePage = () => {
5884
3891
  includeCollection: true,
5885
3892
  includeTemplate: !!collection.templates
5886
3893
  };
5887
- return /* @__PURE__ */ React.createElement(GetDocument, {
3894
+ return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(GetDocument, {
5888
3895
  cms,
5889
3896
  collectionName: collection.name,
5890
3897
  relativePath
@@ -5895,7 +3902,7 @@ const CollectionUpdatePage = () => {
5895
3902
  relativePath,
5896
3903
  collection,
5897
3904
  mutationInfo
5898
- }));
3905
+ })));
5899
3906
  }));
5900
3907
  };
5901
3908
  const RenderForm = ({
@@ -5941,7 +3948,7 @@ const RenderForm = ({
5941
3948
  const windowWidth = useWindowWidth();
5942
3949
  const renderNavToggle = windowWidth < navBreakpoint + 1;
5943
3950
  const headerPadding = renderNavToggle ? "px-20" : "px-6";
5944
- return /* @__PURE__ */ React.createElement(PageWrapper, null, /* @__PURE__ */ React.createElement(React.Fragment, null, ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode) ? /* @__PURE__ */ React.createElement(LocalWarning, null) : /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
3951
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode) ? /* @__PURE__ */ React.createElement(LocalWarning, null) : /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
5945
3952
  className: `py-4 border-b border-gray-200 bg-white ${headerPadding}`
5946
3953
  }, /* @__PURE__ */ React.createElement("div", {
5947
3954
  className: "max-w-form mx-auto"
@@ -5961,7 +3968,7 @@ const RenderForm = ({
5961
3968
  }))), /* @__PURE__ */ React.createElement(FormBuilder, {
5962
3969
  form,
5963
3970
  onPristineChange: setFormIsPristine
5964
- })));
3971
+ }));
5965
3972
  };
5966
3973
  const ScreenPage = () => {
5967
3974
  const { screenName } = useParams();
@@ -6052,9 +4059,30 @@ const PreviewInner = ({ preview, config }) => {
6052
4059
  ...config
6053
4060
  });
6054
4061
  };
4062
+ const CheckSchema = ({
4063
+ schemaJson,
4064
+ children
4065
+ }) => {
4066
+ const cms = useCMS();
4067
+ const api = new TinaAdminApi(cms);
4068
+ const url = api.api.contentApiUrl;
4069
+ useEffect(() => {
4070
+ if (schemaJson && cms) {
4071
+ api.checkGraphqlSchema({
4072
+ localSchema: schemaJson
4073
+ }).then((x) => {
4074
+ if (x === false) {
4075
+ cms.alerts.error("GraphQL Schema Mismatch. Editing may not work. If you just switched branches, try going back to the previous branch");
4076
+ }
4077
+ });
4078
+ }
4079
+ }, [cms, JSON.stringify(schemaJson || {}), url]);
4080
+ return children;
4081
+ };
6055
4082
  const TinaAdmin = ({
6056
4083
  preview,
6057
- config
4084
+ config,
4085
+ schemaJson
6058
4086
  }) => {
6059
4087
  const isSSR2 = typeof window === "undefined";
6060
4088
  const { edit } = useEditState();
@@ -6065,9 +4093,18 @@ const TinaAdmin = ({
6065
4093
  return /* @__PURE__ */ React.createElement(Layout, null, /* @__PURE__ */ React.createElement(LoginPage, null));
6066
4094
  }
6067
4095
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => {
4096
+ var _a, _b, _c;
6068
4097
  const isTinaAdminEnabled = cms.flags.get("tina-admin") === false ? false : true;
6069
4098
  if (isTinaAdminEnabled) {
6070
- return /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(SetPreviewFlag, {
4099
+ const tinaClient = (_a = cms.api) == null ? void 0 : _a.tina;
4100
+ const collectionWithRouter = (_c = (_b = tinaClient == null ? void 0 : tinaClient.schema) == null ? void 0 : _b.config) == null ? void 0 : _c.collections.find((x) => {
4101
+ var _a2;
4102
+ return typeof ((_a2 = x == null ? void 0 : x.ui) == null ? void 0 : _a2.router) === "function";
4103
+ });
4104
+ const hasRouter = Boolean(collectionWithRouter);
4105
+ return /* @__PURE__ */ React.createElement(CheckSchema, {
4106
+ schemaJson
4107
+ }, /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(SetPreviewFlag, {
6071
4108
  preview,
6072
4109
  cms
6073
4110
  }), /* @__PURE__ */ React.createElement(Routes, null, preview && /* @__PURE__ */ React.createElement(Route, {
@@ -6109,11 +4146,11 @@ const TinaAdmin = ({
6109
4146
  }), /* @__PURE__ */ React.createElement(Route, {
6110
4147
  path: "/",
6111
4148
  element: /* @__PURE__ */ React.createElement(MaybeRedirectToPreview, {
6112
- redirect: !!preview
4149
+ redirect: !!preview && hasRouter
6113
4150
  }, /* @__PURE__ */ React.createElement(DefaultWrapper, {
6114
4151
  cms
6115
4152
  }, /* @__PURE__ */ React.createElement(DashboardPage, null)))
6116
- })));
4153
+ }))));
6117
4154
  } else {
6118
4155
  return /* @__PURE__ */ React.createElement(Layout, null, /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
6119
4156
  path: "logout",
@@ -6160,4 +4197,4 @@ const defineStaticConfig = (config) => {
6160
4197
  return config;
6161
4198
  };
6162
4199
  const defineConfig = defineStaticConfig;
6163
- export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, RouteMappingPlugin, TinaAdmin, TinaAdminApi, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, TinaDataProvider, assertShape, createClient, TinaCMSProvider2 as default, defineConfig, defineLegacyConfig, defineSchema, defineStaticConfig, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useGraphqlForms, useTinaAuthRedirect };
4200
+ export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, RouteMappingPlugin, TinaAdmin, TinaAdminApi, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, assertShape, asyncPoll, createClient, TinaCMSProvider2 as default, defineConfig, defineLegacyConfig, defineSchema, defineStaticConfig, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useTinaAuthRedirect };