tinacms 0.66.8 → 0.67.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.js CHANGED
@@ -30,8 +30,8 @@ var __objRest = (source, exclude) => {
30
30
  return target;
31
31
  };
32
32
  (function(global, factory) {
33
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("graphql-tag"), require("styled-components"), require("yup"), require("@tinacms/sharedctx"), require("final-form"), require("url-pattern"), require("react-router-dom"), require("@headlessui/react")) : typeof define === "function" && define.amd ? define(["exports", "@tinacms/toolkit", "graphql", "lodash.set", "react", "graphql-tag", "styled-components", "yup", "@tinacms/sharedctx", "final-form", "url-pattern", "react-router-dom", "@headlessui/react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
34
- })(this, function(exports2, toolkit, G, set, React, gql$1, styled, yup, sharedctx, finalForm, UrlPattern, reactRouterDom, react) {
33
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("final-form"), require("@tinacms/schema-tools"), require("graphql-tag"), require("yup"), require("styled-components"), require("@tinacms/sharedctx"), require("url-pattern"), require("react-router-dom"), require("@headlessui/react")) : typeof define === "function" && define.amd ? define(["exports", "@tinacms/toolkit", "graphql", "lodash.set", "react", "final-form", "@tinacms/schema-tools", "graphql-tag", "yup", "styled-components", "@tinacms/sharedctx", "url-pattern", "react-router-dom", "@headlessui/react"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
34
+ })(this, function(exports2, toolkit, G, set, React, finalForm, schemaTools, gql$1, yup, styled, sharedctx, UrlPattern, reactRouterDom, react) {
35
35
  "use strict";
36
36
  function _interopDefaultLegacy(e) {
37
37
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
@@ -60,8 +60,8 @@ var __objRest = (source, exclude) => {
60
60
  var set__default = /* @__PURE__ */ _interopDefaultLegacy(set);
61
61
  var React__default = /* @__PURE__ */ _interopDefaultLegacy(React);
62
62
  var gql__default = /* @__PURE__ */ _interopDefaultLegacy(gql$1);
63
- var styled__default = /* @__PURE__ */ _interopDefaultLegacy(styled);
64
63
  var yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
64
+ var styled__default = /* @__PURE__ */ _interopDefaultLegacy(styled);
65
65
  var UrlPattern__default = /* @__PURE__ */ _interopDefaultLegacy(UrlPattern);
66
66
  function popupWindow(url, title, window2, w, h) {
67
67
  const y = window2.top.outerHeight / 2 + window2.top.screenY - h / 2;
@@ -396,1306 +396,2561 @@ var __objRest = (source, exclude) => {
396
396
  throw new Error(`Expected an instance of GraphQLUnionType for type ${type.name}`);
397
397
  }
398
398
  }
399
- const isNodeField = (type) => {
400
- if (G__namespace.isUnionType(type)) {
401
- return type.getTypes().every((type2) => {
402
- return type2.getInterfaces().find((intfc) => intfc.name === "Node");
403
- });
404
- } else if (G__namespace.isObjectType(type)) {
405
- return !!type.getInterfaces().find((intfc) => intfc.name === "Node");
406
- } else if (G__namespace.isInterfaceType(type)) {
407
- if (type.name === "Node") {
408
- return true;
409
- }
410
- } else {
411
- throw new Error(`Expected GraphQLObjectType or GraphQLUnionType for isNodeField check`);
412
- }
413
- };
414
- const isConnectionField = (type) => {
415
- if (G__namespace.isObjectType(type)) {
416
- return !!type.getInterfaces().find((intfc) => intfc.name === "Connection");
417
- } else {
418
- throw new Error(`Expected GraphQLObjectType for isCollectionField check`);
419
- }
420
- };
421
- const getObjectField = (object, selectionNode) => {
422
- return object.getFields()[selectionNode.name.value];
423
- };
424
- const getSelectedUnionType = (unionType, selectionNode) => {
425
- return unionType.getTypes().find((type) => type.name === selectionNode.typeCondition.name.value);
399
+ const createClient = ({
400
+ clientId,
401
+ isLocalClient = true,
402
+ branch,
403
+ tinaioConfig,
404
+ schema
405
+ }) => {
406
+ return isLocalClient ? new LocalClient({ schema }) : new Client({
407
+ clientId: clientId || "",
408
+ branch: branch || "main",
409
+ tokenStorage: "LOCAL_STORAGE",
410
+ tinaioConfig,
411
+ schema
412
+ });
426
413
  };
427
- function ensureNodeField(field) {
428
- if (!isNodeField(field)) {
429
- throw new Error(`Expected field to implement Node interface`);
430
- }
431
- }
432
- function ensureUnionType(type) {
433
- if (!G__namespace.isUnionType(type)) {
434
- throw new Error(`Expected type to be GraphQLUnionType`);
435
- }
436
- }
437
- function ensureObjectType(type) {
438
- if (!G__namespace.isObjectType(type)) {
439
- console.log(type);
440
- throw new Error(`Expected type to be GraphQLObjectType`);
441
- }
442
- }
443
- function ensureOperationDefinition(type) {
444
- if (type.kind !== "OperationDefinition") {
445
- throw new Error(`Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`);
414
+ function assertShape(value, yupSchema, errorMessage) {
415
+ const shape = yupSchema(yup__namespace);
416
+ try {
417
+ shape.validateSync(value);
418
+ } catch (e) {
419
+ const message = errorMessage || `Failed to assertShape - ${e.message}`;
420
+ throw new Error(message);
446
421
  }
447
422
  }
448
- function getNameAndAlias(fieldNode, list) {
449
- return {
450
- name: fieldNode.name.value,
451
- alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
452
- list: !!list
453
- };
454
- }
455
- const node = G__namespace.parse(`
456
- query Sample {
457
- _internalSys: sys {
458
- path
459
- collection {
460
- name
461
- }
462
- }
463
- form
464
- values
465
- }`);
466
- const metaFields = node.definitions[0].selectionSet.selections;
467
- const NOOP = "This is either an error or is not yet supported";
468
- const UNEXPECTED = "Formify encountered an unexpected error, please contact support";
469
- const DATA_NODE_NAME = "data";
470
- const EDGES_NODE_NAME = "edges";
471
- const NODE_NAME = "node";
472
- const COLLECTION_FIELD_NAME = "getCollection";
473
- const COLLECTIONS_FIELD_NAME = "getCollections";
474
- const COLLECTIONS_DOCUMENTS_NAME = "documents";
475
- class FormifyError extends Error {
476
- constructor(code, details) {
477
- let message;
478
- switch (code) {
479
- case "NOOP":
480
- message = NOOP;
481
- break;
482
- case "UNEXPECTED":
483
- message = UNEXPECTED;
484
- break;
485
- default:
486
- message = "";
487
- break;
488
- }
489
- super(`${message} ${details || ""}`);
490
- this.name = "FormifyError";
423
+ function safeAssertShape(value, yupSchema) {
424
+ try {
425
+ assertShape(value, yupSchema);
426
+ return true;
427
+ } catch (e) {
428
+ return false;
491
429
  }
492
430
  }
493
- const formify = async ({
494
- schema,
431
+ function useGraphqlFormsUnstable({
432
+ variables,
433
+ onSubmit,
495
434
  query,
496
- getOptimizedQuery
497
- }) => {
498
- const nodes = [];
499
- const documentNode = G__namespace.parse(query);
500
- const visitor2 = {
501
- OperationDefinition: (node2) => {
502
- if (!node2.name) {
503
- return __spreadProps(__spreadValues({}, node2), {
504
- name: {
505
- kind: "Name",
506
- value: `QueryOperation`
507
- }
508
- });
435
+ formify: formify2,
436
+ eventList
437
+ }) {
438
+ const cms = toolkit.useCMS();
439
+ const state = useFormify({
440
+ query,
441
+ cms,
442
+ variables,
443
+ formify: formify2,
444
+ eventList,
445
+ onSubmit
446
+ });
447
+ return [state.data, state.status !== "done"];
448
+ }
449
+ function useGraphqlForms({
450
+ variables,
451
+ onSubmit,
452
+ formify: formify2 = null,
453
+ query
454
+ }) {
455
+ const cms = toolkit.useCMS();
456
+ const [formValues, setFormValues] = React__default["default"].useState({});
457
+ const [data, setData] = React__default["default"].useState(null);
458
+ const [initialData, setInitialData] = React__default["default"].useState({});
459
+ const [pendingReset, setPendingReset] = React__default["default"].useState(null);
460
+ const [isLoading, setIsLoading] = React__default["default"].useState(true);
461
+ const [newUpdate, setNewUpdate] = React__default["default"].useState(null);
462
+ const { currentBranch } = toolkit.useBranchData();
463
+ const updateData = async () => {
464
+ var _a;
465
+ if (newUpdate) {
466
+ const newValue = finalForm.getIn(formValues, newUpdate.get);
467
+ const activeForm = finalForm.getIn(data, [newUpdate.queryName, "form"].join("."));
468
+ if (!activeForm) {
469
+ throw new Error(`Unable to find form for query ${newUpdate.queryName}`);
509
470
  }
510
- return node2;
511
- }
512
- };
513
- const documentNodeWithName = G.visit(documentNode, visitor2);
514
- const optimizedQuery = await getOptimizedQuery(documentNodeWithName);
515
- const typeInfo = new G__namespace.TypeInfo(schema);
516
- const formifyConnection = ({
517
- namedFieldType,
518
- selectionNode,
519
- path
520
- }) => {
521
- ensureObjectType(namedFieldType);
522
- return __spreadProps(__spreadValues({}, selectionNode), {
523
- selectionSet: {
524
- kind: "SelectionSet",
525
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
526
- switch (selectionNode2.kind) {
527
- case "Field":
528
- if (selectionNode2.name.value === EDGES_NODE_NAME) {
529
- const edgeField = namedFieldType.getFields()[EDGES_NODE_NAME];
530
- const edgeType = G__namespace.getNamedType(edgeField.type);
531
- ensureObjectType(edgeType);
532
- return __spreadProps(__spreadValues({}, selectionNode2), {
533
- selectionSet: {
534
- kind: "SelectionSet",
535
- selections: selectionNode2.selectionSet.selections.map((subSelectionNode) => {
536
- switch (subSelectionNode.kind) {
537
- case "Field":
538
- if (subSelectionNode.name.value === NODE_NAME) {
539
- const nodeField = edgeType.getFields()[NODE_NAME];
540
- return formifyNode({
541
- fieldOrInlineFragmentNode: subSelectionNode,
542
- parentType: nodeField.type,
543
- path: [
544
- ...path,
545
- getNameAndAlias(selectionNode2),
546
- getNameAndAlias(subSelectionNode, true)
547
- ]
548
- });
549
- } else {
550
- return subSelectionNode;
551
- }
552
- default:
553
- throw new FormifyError("NOOP");
554
- }
555
- })
556
- }
557
- });
558
- }
559
- return selectionNode2;
560
- default:
561
- throw new FormifyError("UNEXPECTED");
562
- }
563
- })
471
+ if (activeForm == null ? void 0 : activeForm.paths) {
472
+ const asyncUpdate = (_a = activeForm.paths) == null ? void 0 : _a.find((p) => p.dataPath.join(".") === newUpdate.setReference);
473
+ if (asyncUpdate) {
474
+ const res = await cms.api.tina.request(asyncUpdate.queryString, {
475
+ variables: { id: newValue }
476
+ });
477
+ const newData2 = finalForm.setIn(data, newUpdate.set, res.node);
478
+ const newDataAndNewJSONData2 = finalForm.setIn(newData2, newUpdate.set.replace("data", "dataJSON"), newValue);
479
+ setData(newDataAndNewJSONData2);
480
+ setNewUpdate(null);
481
+ return;
482
+ }
564
483
  }
565
- });
566
- };
567
- function formifyNode({
568
- fieldOrInlineFragmentNode,
569
- parentType,
570
- path
571
- }) {
572
- let extraFields = [];
573
- const namedParentType = G__namespace.getNamedType(parentType);
574
- const formifiedNode = __spreadProps(__spreadValues({}, fieldOrInlineFragmentNode), {
575
- selectionSet: {
576
- kind: "SelectionSet",
577
- selections: [
578
- ...fieldOrInlineFragmentNode.selectionSet.selections.map((selectionNode) => {
579
- switch (selectionNode.kind) {
580
- case "InlineFragment":
581
- if (G__namespace.isInterfaceType(namedParentType)) {
582
- const type2 = schema.getImplementations(namedParentType).objects[selectionNode.typeCondition.name.value];
583
- return formifyNode({
584
- fieldOrInlineFragmentNode: selectionNode,
585
- parentType: type2,
586
- path
587
- });
588
- }
589
- ensureUnionType(namedParentType);
590
- const type = getSelectedUnionType(namedParentType, selectionNode);
591
- return formifyNode({
592
- fieldOrInlineFragmentNode: selectionNode,
593
- parentType: type,
594
- path
595
- });
596
- case "Field":
597
- if (selectionNode.name.value === DATA_NODE_NAME) {
598
- extraFields = metaFields;
599
- if (G__namespace.isObjectType(namedParentType)) {
600
- const field = getObjectField(namedParentType, selectionNode);
601
- const namedType = G__namespace.getNamedType(field.type);
602
- ensureObjectType(namedType);
603
- return __spreadProps(__spreadValues({}, selectionNode), {
604
- selectionSet: {
605
- kind: "SelectionSet",
606
- selections: [
607
- ...selectionNode.selectionSet.selections.map((subSelectionNode) => {
608
- switch (subSelectionNode.kind) {
609
- case "Field":
610
- const subSelectionField = getObjectField(namedType, subSelectionNode);
611
- if (!subSelectionField) {
612
- return subSelectionNode;
613
- }
614
- return formifyField({
615
- fieldNode: subSelectionNode,
616
- parentType: field.type,
617
- path: [
618
- ...path,
619
- getNameAndAlias(subSelectionNode, G__namespace.isListType(subSelectionField.type))
620
- ]
621
- });
622
- default:
623
- throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
624
- }
625
- })
626
- ]
627
- }
628
- });
629
- }
630
- return selectionNode;
631
- }
632
- return selectionNode;
633
- default:
634
- throw new FormifyError("UNEXPECTED");
484
+ if (newUpdate.lookup) {
485
+ const field = getFieldUpdate(newUpdate, activeForm, formValues);
486
+ if (field && field.typeMap) {
487
+ newValue.forEach((item) => {
488
+ if (!item.__typename) {
489
+ item["__typename"] = field.typeMap[item._template];
635
490
  }
636
- }),
637
- ...extraFields
638
- ]
639
- }
640
- });
641
- return formifiedNode;
642
- }
643
- const formifyField = ({
644
- fieldNode,
645
- parentType,
646
- path
647
- }) => {
648
- const namedParentType = G__namespace.getNamedType(parentType);
649
- ensureObjectType(namedParentType);
650
- const field = getObjectField(namedParentType, fieldNode);
651
- if (!field) {
652
- if (fieldNode.name.value === "__typename") {
653
- return fieldNode;
654
- } else {
655
- throw new FormifyError("UNEXPECTED", `field with no associated type ${fieldNode.name.value}`);
491
+ });
492
+ }
656
493
  }
494
+ const newData = finalForm.setIn(data, newUpdate.set, newValue);
495
+ const newDataAndNewJSONData = finalForm.setIn(newData, newUpdate.set.replace("data", "dataJSON"), newValue);
496
+ setData(newDataAndNewJSONData);
497
+ setNewUpdate(null);
657
498
  }
658
- const namedType = G__namespace.getNamedType(field.type);
659
- if (G__namespace.isScalarType(namedType)) {
660
- return fieldNode;
499
+ };
500
+ React__default["default"].useEffect(() => {
501
+ updateData();
502
+ }, [JSON.stringify(formValues)]);
503
+ React__default["default"].useEffect(() => {
504
+ if (pendingReset) {
505
+ setData(__spreadProps(__spreadValues({}, data), { [pendingReset]: initialData[pendingReset] }));
506
+ setPendingReset(null);
661
507
  }
662
- return __spreadProps(__spreadValues({}, fieldNode), {
663
- selectionSet: {
664
- kind: "SelectionSet",
665
- selections: [
666
- ...fieldNode.selectionSet.selections.map((selectionNode) => {
667
- switch (selectionNode.kind) {
668
- case "Field":
669
- if (selectionNode.name.value === "__typename") {
670
- return selectionNode;
671
- }
672
- ensureObjectType(namedType);
673
- const field2 = getObjectField(namedType, selectionNode);
674
- if (!field2) {
675
- return fieldNode;
676
- }
677
- if (G__namespace.isScalarType(G__namespace.getNamedType(field2.type))) {
678
- return selectionNode;
679
- }
680
- return __spreadProps(__spreadValues({}, selectionNode), {
681
- selectionSet: {
682
- kind: "SelectionSet",
683
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
684
- switch (selectionNode2.kind) {
685
- case "Field":
686
- if (selectionNode2.name.value === "__typename") {
687
- return selectionNode2;
688
- }
689
- return formifyField({
690
- fieldNode: selectionNode2,
691
- parentType: field2.type,
692
- path
693
- });
694
- case "InlineFragment":
695
- const namedType2 = G__namespace.getNamedType(field2.type);
696
- ensureNodeField(namedType2);
697
- return formifyNode({
698
- fieldOrInlineFragmentNode: selectionNode2,
699
- parentType: field2.type,
700
- path
701
- });
702
- default:
703
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode2.kind}`);
704
- }
705
- })
706
- }
707
- });
708
- case "InlineFragment":
709
- ensureUnionType(namedType);
710
- if (isNodeField(namedType)) {
711
- const parentType2 = getSelectedUnionType(namedType, selectionNode);
712
- return formifyNode({
713
- fieldOrInlineFragmentNode: selectionNode,
714
- parentType: parentType2,
715
- path
716
- });
717
- }
718
- return __spreadProps(__spreadValues({}, selectionNode), {
719
- selectionSet: {
720
- kind: "SelectionSet",
721
- selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
722
- switch (subSelectionNode.kind) {
723
- case "Field":
724
- const parentType2 = getSelectedUnionType(namedType, selectionNode);
725
- return formifyField({
726
- fieldNode: subSelectionNode,
727
- parentType: parentType2,
728
- path
729
- });
730
- default:
731
- throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
732
- }
733
- })
734
- }
508
+ }, [pendingReset]);
509
+ React__default["default"].useEffect(() => {
510
+ if (!query) {
511
+ setIsLoading(false);
512
+ return;
513
+ }
514
+ const useUnstableFormify = (cms == null ? void 0 : cms.flags.get("use-unstable-formify")) === false ? false : true;
515
+ const formIds = [];
516
+ setIsLoading(true);
517
+ cms.api.tina.requestWithForm((gql2) => gql2(query), {
518
+ variables,
519
+ useUnstableFormify
520
+ }).then((payload) => {
521
+ cms.plugins.remove(new toolkit.FormMetaPlugin({ name: "tina-admin-link" }));
522
+ setData(payload);
523
+ setInitialData(payload);
524
+ setIsLoading(false);
525
+ Object.entries(payload).map(([queryName, result]) => {
526
+ formIds.push(queryName);
527
+ const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
528
+ values: yup2.object().required(),
529
+ form: yup2.object().required()
530
+ }));
531
+ if (!canBeFormified) {
532
+ return;
533
+ }
534
+ assertShape(result, (yup2) => yup2.object({
535
+ values: yup2.object().required(),
536
+ form: yup2.object().required()
537
+ }), `Unable to build form shape for fields at ${queryName}`);
538
+ let formConfig = {};
539
+ const formCommon = {
540
+ id: queryName,
541
+ initialValues: result.values,
542
+ reset: () => {
543
+ setPendingReset(queryName);
544
+ },
545
+ onSubmit: async (payload2) => {
546
+ try {
547
+ const params = transformDocumentIntoMutationRequestPayload(payload2, result.form.mutationInfo);
548
+ const variables2 = { params };
549
+ const mutationString = result.form.mutationInfo.string;
550
+ if (onSubmit) {
551
+ onSubmit({
552
+ queryString: mutationString,
553
+ mutationString,
554
+ variables: variables2
735
555
  });
736
- default:
737
- throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
738
- }
739
- })
740
- ]
741
- }
742
- });
743
- };
744
- const formifiedQuery = {
745
- kind: "Document",
746
- definitions: optimizedQuery.definitions.map((definition) => {
747
- typeInfo.enter(definition);
748
- ensureOperationDefinition(definition);
749
- const type = typeInfo.getType();
750
- const namedType = G__namespace.getNamedType(type);
751
- ensureObjectType(namedType);
752
- return __spreadProps(__spreadValues({}, definition), {
753
- selectionSet: {
754
- kind: "SelectionSet",
755
- selections: definition.selectionSet.selections.map((selectionNode) => {
756
- switch (selectionNode.kind) {
757
- case "Field":
758
- const parentType = type;
759
- const namedParentType = G__namespace.getNamedType(parentType);
760
- ensureObjectType(namedParentType);
761
- const field = getObjectField(namedParentType, selectionNode);
762
- const namedFieldType = G__namespace.getNamedType(field.type);
763
- if (isNodeField(namedFieldType)) {
764
- return formifyNode({
765
- fieldOrInlineFragmentNode: selectionNode,
766
- parentType: field.type,
767
- path: [getNameAndAlias(selectionNode)]
768
- });
769
- } else if (isConnectionField(namedFieldType)) {
770
- return formifyConnection({
771
- namedFieldType,
772
- selectionNode,
773
- path: [getNameAndAlias(selectionNode)]
774
- });
775
- }
776
- if (selectionNode.name.value === COLLECTION_FIELD_NAME || selectionNode.name.value === COLLECTIONS_FIELD_NAME) {
777
- return __spreadProps(__spreadValues({}, selectionNode), {
778
- selectionSet: {
779
- kind: "SelectionSet",
780
- selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
781
- switch (selectionNode2.kind) {
782
- case "Field":
783
- if (selectionNode2.name.value === COLLECTIONS_DOCUMENTS_NAME) {
784
- ensureObjectType(namedFieldType);
785
- const n = namedFieldType.getFields()[COLLECTIONS_DOCUMENTS_NAME];
786
- const docType = G__namespace.getNamedType(n.type);
787
- return formifyConnection({
788
- namedFieldType: docType,
789
- selectionNode: selectionNode2,
790
- path: [getNameAndAlias(selectionNode2)]
791
- });
792
- }
793
- return selectionNode2;
794
- default:
795
- throw new FormifyError("NOOP");
796
- }
797
- })
798
- }
556
+ } else {
557
+ try {
558
+ await cms.api.tina.request(mutationString, {
559
+ variables: variables2
799
560
  });
561
+ cms.alerts.success("Document saved!");
562
+ } catch (e) {
563
+ cms.alerts.error("There was a problem saving your document");
564
+ console.error(e);
800
565
  }
801
- throw new FormifyError("NOOP");
802
- default:
803
- throw new FormifyError("UNEXPECTED");
566
+ }
567
+ } catch (e) {
568
+ console.error(e);
569
+ cms.alerts.error("There was a problem saving your document");
804
570
  }
805
- })
806
- }
807
- });
808
- })
809
- };
810
- nodes.map((node2) => {
811
- const namePath = [];
812
- const aliasPath = [];
813
- node2.path.forEach((p) => {
814
- namePath.push(p.name);
815
- aliasPath.push(p.alias);
816
- if (p.list) {
817
- namePath.push("NUM");
818
- aliasPath.push("NUM");
819
- }
820
- });
821
- JSON.stringify({
822
- namePath: namePath.join("."),
823
- aliasPath: aliasPath.join(".")
824
- }, null, 2);
825
- });
826
- return { formifiedQuery, nodes };
827
- };
828
- const captureBranchName = /^refs\/heads\/(.*)/;
829
- const parseRefForBranchName = (ref) => {
830
- const matches = ref.match(captureBranchName);
831
- return matches[1];
832
- };
833
- class Client {
834
- constructor(_a) {
835
- var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
836
- this.events = new toolkit.EventBus();
837
- this.addPendingContent = async (props) => {
838
- const mutation = `#graphql
839
- mutation addPendingDocumentMutation(
840
- $relativePath: String!
841
- $collection: String!
842
- $template: String
843
- ) {
844
- addPendingDocument(
845
- relativePath: $relativePath
846
- template: $template
847
- collection: $collection
848
- ) {
849
- ... on Document {
850
- sys {
851
- relativePath
852
- path
853
- breadcrumbs
854
- collection {
855
- slug
856
- }
857
- }
858
- }
859
- }
860
- }`;
861
- const result = await this.request(mutation, {
862
- variables: props
863
- });
864
- return result;
865
- };
866
- this.getSchema = async () => {
867
- if (!this.schema) {
868
- const data = await this.request(G.getIntrospectionQuery(), {
869
- variables: {}
870
- });
871
- this.schema = G.buildClientSchema(data);
872
- }
873
- return this.schema;
874
- };
875
- this.getOptimizedQuery = async (documentNode) => {
876
- const data = await this.request(`query GetOptimizedQuery($queryString: String!) {
877
- getOptimizedQuery(queryString: $queryString)
878
- }`, {
879
- variables: { queryString: G.print(documentNode) }
880
- });
881
- return G.parse(data.getOptimizedQuery);
882
- };
883
- this.options = options;
884
- this.setBranch(options.branch);
885
- this.events.subscribe("branch:change", ({ branchName }) => {
886
- this.setBranch(branchName);
887
- });
888
- this.clientId = options.clientId;
889
- switch (tokenStorage) {
890
- case "LOCAL_STORAGE":
891
- this.getToken = async function() {
892
- const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
893
- if (tokens) {
894
- return await this.getRefreshedToken(tokens);
895
- } else {
896
- return {
897
- access_token: null,
898
- id_token: null,
899
- refresh_token: null
900
- };
901
571
  }
902
572
  };
903
- this.setToken = function(token) {
904
- localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
573
+ if (cms.api.tina.schema) {
574
+ const enrichedSchema = cms.api.tina.schema;
575
+ const collection = enrichedSchema.getCollection(result._internalSys.collection.name);
576
+ const template = enrichedSchema.getTemplateForData({
577
+ collection,
578
+ data: result.values
579
+ });
580
+ const formInfo = schemaTools.resolveForm({
581
+ collection,
582
+ basename: collection.name,
583
+ schema: enrichedSchema,
584
+ template
585
+ });
586
+ formConfig = __spreadValues({
587
+ label: formInfo.label,
588
+ fields: formInfo.fields
589
+ }, formCommon);
590
+ } else {
591
+ formConfig = __spreadValues({
592
+ label: result.form.label,
593
+ fields: result.form.fields
594
+ }, formCommon);
595
+ }
596
+ const { createForm, createGlobalForm } = generateFormCreators(cms);
597
+ const SKIPPED = "SKIPPED";
598
+ let form;
599
+ let skipped;
600
+ const skip = () => {
601
+ skipped = SKIPPED;
905
602
  };
906
- break;
907
- case "MEMORY":
908
- this.getToken = async () => {
909
- if (this.token) {
910
- return await this.getRefreshedToken(this.token);
603
+ if (skipped)
604
+ return;
605
+ if (formify2) {
606
+ form = formify2({ formConfig, createForm, createGlobalForm, skip }, cms);
607
+ } else {
608
+ form = createForm(formConfig);
609
+ }
610
+ if (!(form instanceof toolkit.Form)) {
611
+ if (skipped === SKIPPED) {
612
+ return;
613
+ }
614
+ throw new Error("formify must return a form or skip()");
615
+ }
616
+ const { change } = form.finalForm;
617
+ form.finalForm.change = (name, value) => {
618
+ let referenceName = "";
619
+ if (typeof name === "string") {
620
+ referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
911
621
  } else {
912
- return {
913
- access_token: null,
914
- id_token: null,
915
- refresh_token: null
916
- };
622
+ throw new Error(`Expected name to be of type string for FinalForm change callback`);
917
623
  }
624
+ setNewUpdate({
625
+ queryName,
626
+ get: [queryName, "values", name].join("."),
627
+ set: [queryName, "data", name].join("."),
628
+ setReference: [queryName, "data", referenceName].join(".")
629
+ });
630
+ return change(name, value);
918
631
  };
919
- this.setToken = (token) => {
920
- this.token = JSON.stringify(token, null, 2);
921
- };
922
- break;
923
- case "CUSTOM":
924
- if (!options.getTokenFn) {
925
- throw new Error("When CUSTOM token storage is selected, a getTokenFn must be provided");
926
- }
927
- this.getToken = options.getTokenFn;
928
- break;
929
- }
930
- }
931
- get isLocalMode() {
932
- return this.contentApiUrl.includes("localhost");
632
+ const _a = form.finalForm.mutators, { insert, move, remove } = _a, rest = __objRest(_a, ["insert", "move", "remove"]);
633
+ const prepareNewUpdate = (name, lookup) => {
634
+ const extra = {};
635
+ if (lookup) {
636
+ extra["lookup"] = lookup;
637
+ }
638
+ const referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
639
+ setNewUpdate(__spreadValues({
640
+ queryName,
641
+ get: [queryName, "values", name].join("."),
642
+ set: [queryName, "data", name].join("."),
643
+ setReference: [queryName, "data", referenceName].join(".")
644
+ }, extra));
645
+ };
646
+ form.finalForm.mutators = __spreadValues({
647
+ insert: (...args) => {
648
+ const fieldName = args[0];
649
+ prepareNewUpdate(fieldName, fieldName);
650
+ insert(...args);
651
+ },
652
+ move: (...args) => {
653
+ const fieldName = args[0];
654
+ prepareNewUpdate(fieldName, fieldName);
655
+ move(...args);
656
+ },
657
+ remove: (...args) => {
658
+ const fieldName = args[0];
659
+ prepareNewUpdate(fieldName, fieldName);
660
+ remove(...args);
661
+ }
662
+ }, rest);
663
+ form.subscribe(({ values }) => {
664
+ setFormValues(__spreadProps(__spreadValues({}, formValues), { [queryName]: { values } }));
665
+ }, { values: true });
666
+ });
667
+ }).catch((e) => {
668
+ cms.alerts.error("There was a problem setting up forms for your query");
669
+ console.error("There was a problem setting up forms for your query");
670
+ console.error(e);
671
+ setIsLoading(false);
672
+ });
673
+ return () => {
674
+ formIds.forEach((name) => {
675
+ const formPlugin = cms.forms.find(name);
676
+ if (formPlugin) {
677
+ cms.forms.remove(formPlugin);
678
+ }
679
+ });
680
+ };
681
+ }, [query, JSON.stringify(variables), currentBranch]);
682
+ return [data, isLoading];
683
+ }
684
+ const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
685
+ const _a = document, { _collection, __typename, _template } = _a, rest = __objRest(_a, ["_collection", "__typename", "_template"]);
686
+ const params = transformParams(rest);
687
+ const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
688
+ return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
689
+ };
690
+ const transformParams = (data) => {
691
+ if (["string", "number", "boolean"].includes(typeof data)) {
692
+ return data;
933
693
  }
934
- setBranch(branchName) {
935
- var _a, _b, _c;
936
- const encodedBranch = encodeURIComponent(branchName);
937
- this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
938
- this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
939
- this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
940
- this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
694
+ if (Array.isArray(data)) {
695
+ return data.map((item) => transformParams(item));
941
696
  }
942
- async requestWithForm(query, {
943
- variables,
944
- useUnstableFormify
945
- }) {
946
- const schema = await this.getSchema();
947
- let formifiedQuery;
948
- if (useUnstableFormify) {
949
- const res = await formify({
950
- schema,
951
- query: G.print(query(gql__default["default"])),
952
- getOptimizedQuery: this.getOptimizedQuery
697
+ try {
698
+ assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
699
+ const _a = data, { _template, __typename } = _a, rest = __objRest(_a, ["_template", "__typename"]);
700
+ const nested = transformParams(rest);
701
+ return { [_template]: nested };
702
+ } catch (e) {
703
+ if (e.message === "Failed to assertShape - _template is a required field") {
704
+ if (!data) {
705
+ return [];
706
+ }
707
+ const accum = {};
708
+ Object.entries(data).map(([keyName, value]) => {
709
+ accum[keyName] = transformParams(value);
953
710
  });
954
- formifiedQuery = res.formifiedQuery;
711
+ return accum;
955
712
  } else {
956
- formifiedQuery = formify$1(query(gql__default["default"]), schema);
713
+ if (!data) {
714
+ return [];
715
+ }
716
+ throw e;
957
717
  }
958
- return this.request(G.print(formifiedQuery), { variables });
959
718
  }
960
- async request(query, { variables }) {
961
- const res = await fetch(this.contentApiUrl, {
962
- method: "POST",
963
- headers: {
964
- "Content-Type": "application/json",
965
- Authorization: "Bearer " + (await this.getToken()).id_token
966
- },
967
- body: JSON.stringify({
968
- query: typeof query === "function" ? G.print(query(gql__default["default"])) : query,
969
- variables
970
- })
971
- });
972
- if (res.status !== 200) {
973
- throw new Error(`Unable to complete request, ${res.statusText}`);
719
+ };
720
+ const getFieldUpdate = (newUpdate, activeForm, formValues) => {
721
+ const items = newUpdate.lookup.split(".");
722
+ let currentFields = activeForm.fields;
723
+ items.map((item, index) => {
724
+ const lookupName = items.slice(0, index + 1).join(".");
725
+ const value = finalForm.getIn(formValues, [newUpdate.queryName, "values", lookupName].join("."));
726
+ if (isNaN(Number(item))) {
727
+ if (Array.isArray(currentFields)) {
728
+ currentFields = currentFields.find((field) => field.name === item);
729
+ }
730
+ } else {
731
+ const template = currentFields.templates ? currentFields.templates[value._template] : currentFields;
732
+ currentFields = template.fields;
974
733
  }
975
- const json = await res.json();
976
- if (json.errors) {
977
- throw new Error(`Unable to fetch, errors:
978
- ${json.errors.map((error) => error.message).join("\n")}`);
734
+ });
735
+ return currentFields;
736
+ };
737
+ const generateFormCreators = (cms) => {
738
+ const createForm = (formConfig) => {
739
+ const form = new toolkit.Form(formConfig);
740
+ cms.forms.add(form);
741
+ return form;
742
+ };
743
+ const createGlobalForm = (formConfig, options) => {
744
+ const form = new toolkit.Form(formConfig);
745
+ cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
746
+ return form;
747
+ };
748
+ return { createForm, createGlobalForm };
749
+ };
750
+ const generateFormCreatorsUnstable = (cms, showInSidebar) => {
751
+ const createForm = (formConfig) => {
752
+ const form = new toolkit.Form(formConfig);
753
+ if (showInSidebar) {
754
+ cms.forms.add(form);
979
755
  }
980
- return json.data;
981
- }
982
- parseJwt(token) {
983
- const base64Url = token.split(".")[1];
984
- const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
985
- const jsonPayload = decodeURIComponent(atob(base64).split("").map(function(c) {
986
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
987
- }).join(""));
988
- return JSON.parse(jsonPayload);
989
- }
990
- async getRefreshedToken(tokens) {
991
- const { access_token, id_token, refresh_token } = JSON.parse(tokens);
992
- const { exp, iss, client_id } = this.parseJwt(access_token);
993
- if (Date.now() / 1e3 >= exp - 120) {
994
- const refreshResponse = await fetch(iss, {
995
- method: "POST",
996
- headers: {
997
- "Content-Type": "application/x-amz-json-1.1",
998
- "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
999
- },
1000
- body: JSON.stringify({
1001
- ClientId: client_id,
1002
- AuthFlow: "REFRESH_TOKEN_AUTH",
1003
- AuthParameters: {
1004
- REFRESH_TOKEN: refresh_token,
1005
- DEVICE_KEY: null
756
+ return form;
757
+ };
758
+ const createGlobalForm = (formConfig, options) => {
759
+ const form = new toolkit.Form(formConfig);
760
+ if (showInSidebar) {
761
+ cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
762
+ }
763
+ return form;
764
+ };
765
+ return { createForm, createGlobalForm };
766
+ };
767
+ const getValueForBlueprint = (state, path) => {
768
+ const pathArray = path.split(".");
769
+ let latest = state;
770
+ pathArray.every((item, index) => {
771
+ if (item === "[]") {
772
+ const restOfItems = pathArray.slice(index + 1);
773
+ if (latest) {
774
+ const next = [];
775
+ if (Array.isArray(latest)) {
776
+ latest.forEach((latest2, index2) => {
777
+ const res = getValueForBlueprint(latest2, restOfItems.join("."));
778
+ next.push(res);
779
+ });
780
+ } else {
781
+ throw new Error(`Expected value to be an array for "[]" item`);
782
+ }
783
+ if (next.length > 0) {
784
+ latest = next;
785
+ } else {
786
+ latest = void 0;
787
+ }
788
+ }
789
+ return false;
790
+ } else {
791
+ if (latest) {
792
+ latest = latest[item];
793
+ } else {
794
+ latest = void 0;
795
+ }
796
+ }
797
+ return true;
798
+ });
799
+ return latest;
800
+ };
801
+ const getFieldNameOrAlias = (fieldBlueprint) => {
802
+ return fieldBlueprint.path[fieldBlueprint.path.length - 1].alias;
803
+ };
804
+ const spliceLocation = (string, location) => {
805
+ const accum = [];
806
+ let counter = 0;
807
+ string.split(".").forEach((item) => {
808
+ if (item === "[]") {
809
+ accum.push(location[counter]);
810
+ counter++;
811
+ } else {
812
+ accum.push(item);
813
+ }
814
+ });
815
+ return accum.join(".");
816
+ };
817
+ const getPathToChange = (documentBlueprint, formNode, event) => {
818
+ const fieldName = event.field.name;
819
+ const location = [...formNode.location, ...stripIndices(fieldName)];
820
+ const accum = [];
821
+ let counter = 0;
822
+ documentBlueprint.path.forEach((item) => {
823
+ accum.push(item.alias);
824
+ if (item.list) {
825
+ if (location[counter] !== void 0) {
826
+ accum.push(location[counter]);
827
+ counter++;
828
+ }
829
+ }
830
+ });
831
+ return accum.join(".");
832
+ };
833
+ const buildForm = (doc, cms, formify2, showInSidebar = false, onSubmit) => {
834
+ const { createForm, createGlobalForm } = generateFormCreatorsUnstable(cms, showInSidebar);
835
+ const SKIPPED = "SKIPPED";
836
+ let form;
837
+ let skipped;
838
+ const skip = () => {
839
+ skipped = SKIPPED;
840
+ };
841
+ if (skipped)
842
+ return;
843
+ const id = doc._internalSys.path;
844
+ const formCommon = {
845
+ id,
846
+ label: doc.form.label,
847
+ initialValues: doc.values,
848
+ onSubmit: async (payload) => {
849
+ try {
850
+ const params = transformDocumentIntoMutationRequestPayload(payload, doc.form.mutationInfo);
851
+ const variables = { params };
852
+ const mutationString = doc.form.mutationInfo.string;
853
+ if (onSubmit) {
854
+ onSubmit({
855
+ queryString: mutationString,
856
+ mutationString,
857
+ variables
858
+ });
859
+ } else {
860
+ try {
861
+ await cms.api.tina.request(mutationString, {
862
+ variables
863
+ });
864
+ cms.alerts.success("Document saved!");
865
+ } catch (e) {
866
+ cms.alerts.error("There was a problem saving your document");
867
+ console.error(e);
1006
868
  }
1007
- })
1008
- });
1009
- if (refreshResponse.status !== 200) {
1010
- throw new Error("Unable to refresh auth tokens");
869
+ }
870
+ } catch (e) {
871
+ console.error(e);
872
+ cms.alerts.error("There was a problem saving your document");
1011
873
  }
1012
- const responseJson = await refreshResponse.json();
1013
- const newToken = {
1014
- access_token: responseJson.AuthenticationResult.AccessToken,
1015
- id_token: responseJson.AuthenticationResult.IdToken,
1016
- refresh_token
1017
- };
1018
- this.setToken(newToken);
1019
- return Promise.resolve(newToken);
1020
874
  }
1021
- return Promise.resolve({ access_token, id_token, refresh_token });
875
+ };
876
+ let formConfig = {};
877
+ if (cms.api.tina.schema) {
878
+ const enrichedSchema = cms.api.tina.schema;
879
+ const collection = enrichedSchema.getCollection(doc._internalSys.collection.name);
880
+ const template = enrichedSchema.getTemplateForData({
881
+ collection,
882
+ data: doc.values
883
+ });
884
+ const formInfo = schemaTools.resolveForm({
885
+ collection,
886
+ basename: collection.name,
887
+ schema: enrichedSchema,
888
+ template
889
+ });
890
+ formConfig = __spreadValues({
891
+ label: formInfo.label,
892
+ fields: formInfo.fields
893
+ }, formCommon);
894
+ } else {
895
+ formConfig = __spreadValues({
896
+ label: doc.form.label,
897
+ fields: doc.form.fields
898
+ }, formCommon);
1022
899
  }
1023
- async isAuthorized() {
1024
- return this.isAuthenticated();
900
+ if (formify2) {
901
+ form = formify2({
902
+ formConfig,
903
+ createForm,
904
+ createGlobalForm,
905
+ skip
906
+ }, cms);
907
+ } else {
908
+ form = createForm(formConfig);
1025
909
  }
1026
- async isAuthenticated() {
1027
- return !!await this.getUser();
910
+ if (!(form instanceof toolkit.Form)) {
911
+ if (skipped === SKIPPED) {
912
+ return;
913
+ }
914
+ throw new Error("formify must return a form or skip()");
1028
915
  }
1029
- async authenticate() {
1030
- const token = await authenticate(this.clientId, this.frontendUrl);
1031
- this.setToken(token);
1032
- return token;
916
+ return form;
917
+ };
918
+ const formNodeId = (formNode) => {
919
+ return spliceLocation(formNode.documentBlueprintId, formNode.location) + formNode.documentFormId;
920
+ };
921
+ const formNodePath = (formNode) => {
922
+ return spliceLocation(formNode.documentBlueprintId, formNode.location);
923
+ };
924
+ const formNodeNotIn = (formNode, formNodes) => {
925
+ return !formNodes.find((fn) => formNodeId(fn) === formNodeId(formNode));
926
+ };
927
+ const sequential = async (items, callback) => {
928
+ const accum = [];
929
+ if (!items) {
930
+ return [];
1033
931
  }
1034
- async fetchWithToken(input, init) {
1035
- const headers = (init == null ? void 0 : init.headers) || {};
1036
- return await fetch(input, __spreadProps(__spreadValues({}, init), {
1037
- headers: new Headers(__spreadValues({
1038
- Authorization: "Bearer " + (await this.getToken()).id_token
1039
- }, headers))
1040
- }));
932
+ const reducePromises = async (previous, endpoint) => {
933
+ const prev = await previous;
934
+ if (prev) {
935
+ accum.push(prev);
936
+ }
937
+ return callback(endpoint, accum.length);
938
+ };
939
+ const result = await items.reduce(reducePromises, Promise.resolve());
940
+ if (result) {
941
+ accum.push(result);
1041
942
  }
1042
- async getUser() {
1043
- if (!this.clientId) {
1044
- return null;
943
+ return accum;
944
+ };
945
+ const getFormNodesStartingWith = (string, state) => {
946
+ return state.formNodes.filter((subFormNode) => {
947
+ return subFormNode.documentBlueprintId.startsWith(string);
948
+ });
949
+ };
950
+ const getFormNodesForField = (fieldBlueprint, formNode, event, state) => {
951
+ const pathToChange = getPathToChange(fieldBlueprint, formNode, event);
952
+ const formNodes = getFormNodesStartingWith(fieldBlueprint.id, state);
953
+ const eventLocation = [
954
+ ...formNode.location,
955
+ ...stripIndices(event.field.name)
956
+ ];
957
+ const existing = finalForm.getIn(state.data, pathToChange);
958
+ return { pathToChange, formNodes, eventLocation, existing };
959
+ };
960
+ const getBlueprintAliasPath = (blueprint) => {
961
+ const namePath = [];
962
+ const aliasPath = [];
963
+ blueprint.path.forEach((p) => {
964
+ namePath.push(p.name);
965
+ aliasPath.push(p.alias);
966
+ if (p.list) {
967
+ namePath.push("[]");
968
+ aliasPath.push("[]");
1045
969
  }
1046
- const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
1047
- try {
1048
- const res = await this.fetchWithToken(url, {
1049
- method: "GET"
1050
- });
1051
- const val = await res.json();
1052
- if (!res.status.toString().startsWith("2")) {
1053
- console.error(val.error);
1054
- return null;
1055
- }
1056
- return val;
1057
- } catch (e) {
1058
- console.error(e);
1059
- return null;
970
+ });
971
+ return aliasPath.join(".");
972
+ };
973
+ const getBlueprintFieldsForEvent = (blueprint, event) => {
974
+ return blueprint.fields.filter((fbp) => {
975
+ if (getBlueprintNamePath(fbp) === getEventPath(event, blueprint)) {
976
+ return true;
1060
977
  }
1061
- }
1062
- async listBranches() {
1063
- const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
1064
- const res = await this.fetchWithToken(url, {
1065
- method: "GET"
1066
- });
1067
- return res.json();
1068
- }
1069
- async createBranch({ baseBranch, branchName }) {
1070
- const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
1071
- try {
1072
- const res = await this.fetchWithToken(url, {
1073
- method: "POST",
1074
- body: JSON.stringify({
1075
- baseBranch,
1076
- branchName
1077
- }),
1078
- headers: {
1079
- "Content-Type": "application/json"
1080
- }
1081
- });
1082
- return await res.json().then((r) => parseRefForBranchName(r.data.ref));
1083
- } catch (error) {
1084
- console.error("There was an error creating a new branch.", error);
1085
- return null;
978
+ }).filter((fbp) => {
979
+ return filterFieldBlueprintsByParentTypename(fbp, event.field.data.tinaField.parentTypename);
980
+ });
981
+ };
982
+ const filterFieldBlueprintsByParentTypename = (fbp, typename) => {
983
+ let lastDisambiguator;
984
+ fbp.path.forEach((path) => {
985
+ if (path.parentTypename) {
986
+ lastDisambiguator = path.parentTypename;
1086
987
  }
988
+ });
989
+ if (lastDisambiguator) {
990
+ return typename === lastDisambiguator;
991
+ } else {
992
+ return true;
1087
993
  }
1088
- }
1089
- const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
1090
- class LocalClient extends Client {
1091
- constructor(props) {
1092
- const clientProps = {
1093
- clientId: "",
1094
- branch: "",
1095
- customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
1096
- };
1097
- super(clientProps);
994
+ };
995
+ const getBlueprintNamePath = (blueprint, disambiguator) => {
996
+ const namePath = [];
997
+ blueprint.path.forEach((p) => {
998
+ if (disambiguator) {
999
+ if (p.parentTypename) {
1000
+ namePath.push(p.parentTypename);
1001
+ }
1002
+ }
1003
+ namePath.push(p.name);
1004
+ if (p.list) {
1005
+ namePath.push("[]");
1006
+ }
1007
+ });
1008
+ return namePath.join(".");
1009
+ };
1010
+ const getEventPath = (event, blueprint) => {
1011
+ const stringArray = event.field.name.split(".");
1012
+ const eventPath = stringArray.map((item) => {
1013
+ if (isNaN(Number(item))) {
1014
+ return item;
1015
+ }
1016
+ return `[]`;
1017
+ }).join(".");
1018
+ const items = [blueprint.id, DATA_NODE_NAME$1, eventPath];
1019
+ const isList = event.field.data.tinaField.list;
1020
+ if (isList && !eventPath.endsWith("[]")) {
1021
+ items.push(`[]`);
1098
1022
  }
1099
- async isAuthorized() {
1100
- return true;
1023
+ return items.join(".");
1024
+ };
1025
+ const stripIndices = (string) => {
1026
+ const accum = [];
1027
+ const stringArray = string.split(".");
1028
+ stringArray.forEach((item) => {
1029
+ if (isNaN(item))
1030
+ ;
1031
+ else {
1032
+ accum.push(Number(item));
1033
+ }
1034
+ });
1035
+ return accum;
1036
+ };
1037
+ const replaceRealNum = (string) => {
1038
+ const stringArray = string.split(".");
1039
+ return stringArray.map((item) => {
1040
+ if (isNaN(item)) {
1041
+ return item;
1042
+ }
1043
+ return "[]";
1044
+ }).join(".");
1045
+ };
1046
+ const getMatchName = ({ field, prefix, blueprint }) => {
1047
+ const fieldName = field.list ? `${field.name}.[]` : field.name;
1048
+ const blueprintName = getBlueprintNamePath(blueprint);
1049
+ const extra = [];
1050
+ if (prefix) {
1051
+ extra.push(prefix);
1101
1052
  }
1102
- async isAuthenticated() {
1103
- return true;
1053
+ const matchName = [blueprintName, DATA_NODE_NAME$1, ...extra, fieldName].join(".");
1054
+ return { matchName, fieldName };
1055
+ };
1056
+ const getFormNodesFromEvent = (state, event) => {
1057
+ const formNodes = state.formNodes.filter((formNode) => formNode.documentFormId === event.formId);
1058
+ return formNodes;
1059
+ };
1060
+ const DATA_NODE_NAME$1 = "data";
1061
+ const printEvent = (event) => {
1062
+ var _a, _b;
1063
+ return {
1064
+ type: event.type,
1065
+ value: event.value,
1066
+ previousValue: event.previousValue,
1067
+ mutationType: event.mutationType,
1068
+ formId: event.formId,
1069
+ field: {
1070
+ data: (_a = event.field) == null ? void 0 : _a.data,
1071
+ name: (_b = event.field) == null ? void 0 : _b.name
1072
+ }
1073
+ };
1074
+ };
1075
+ const getFormNodeBlueprint = (formNode, state) => {
1076
+ return state.blueprints.find((d) => d.id === formNode.documentBlueprintId);
1077
+ };
1078
+ const getMoveMapping = (existing, from, to) => {
1079
+ const newOrderObject = {};
1080
+ if (from < to) {
1081
+ existing.map((_, i) => {
1082
+ if (i === from) {
1083
+ newOrderObject[i] = to;
1084
+ return;
1085
+ }
1086
+ if (i > from) {
1087
+ if (i < to) {
1088
+ newOrderObject[i] = i - 1;
1089
+ return;
1090
+ } else {
1091
+ if (i === to) {
1092
+ newOrderObject[i] = i - 1;
1093
+ return;
1094
+ }
1095
+ newOrderObject[i] = i;
1096
+ return;
1097
+ }
1098
+ } else {
1099
+ newOrderObject[i] = i;
1100
+ return;
1101
+ }
1102
+ });
1103
+ } else {
1104
+ existing.map((_, i) => {
1105
+ if (i === from) {
1106
+ newOrderObject[i] = to;
1107
+ return;
1108
+ }
1109
+ if (i > to) {
1110
+ if (i < from) {
1111
+ newOrderObject[i] = i + 1;
1112
+ return;
1113
+ } else {
1114
+ newOrderObject[i] = i;
1115
+ return;
1116
+ }
1117
+ } else {
1118
+ if (i === to) {
1119
+ newOrderObject[i] = i + 1;
1120
+ return;
1121
+ }
1122
+ newOrderObject[i] = i;
1123
+ return;
1124
+ }
1125
+ });
1104
1126
  }
1105
- }
1106
- function ModalBuilder(modalProps) {
1107
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalPopup, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalBody, {
1108
- padded: true
1109
- }, /* @__PURE__ */ React__default["default"].createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default["default"].createElement(ErrorLabel, null, modalProps.error)), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default["default"].createElement(AsyncButton, __spreadValues({
1110
- key: action.name
1111
- }, action))))));
1112
- }
1113
- const ErrorLabel = styled__default["default"].p`
1114
- color: var(--tina-color-error) !important;
1115
- `;
1116
- const AsyncButton = ({ name, primary, action }) => {
1117
- const [submitting, setSubmitting] = React.useState(false);
1118
- const onClick = React.useCallback(async () => {
1119
- setSubmitting(true);
1120
- try {
1121
- await action();
1122
- setSubmitting(false);
1123
- } catch (e) {
1124
- setSubmitting(false);
1125
- throw e;
1127
+ return newOrderObject;
1128
+ };
1129
+ const matchLocation = (eventLocation, formNode) => {
1130
+ return eventLocation.every((item, index) => item === formNode.location[index]);
1131
+ };
1132
+ const bumpLocation = (location) => {
1133
+ return location.map((item, index) => {
1134
+ if (index === location.length - 1) {
1135
+ return item + 1;
1126
1136
  }
1127
- }, [action, setSubmitting]);
1128
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
1129
- variant: primary ? "primary" : "secondary",
1130
- onClick,
1131
- busy: submitting,
1132
- disabled: submitting
1133
- }, submitting && /* @__PURE__ */ React__default["default"].createElement(toolkit.LoadingDots, null), !submitting && name);
1137
+ return item;
1138
+ });
1134
1139
  };
1135
- const TINA_AUTH_CONFIG = "tina_auth_config";
1136
- const useTinaAuthRedirect = () => {
1137
- React.useEffect(() => {
1138
- const urlParams = new URLSearchParams(window.location.search);
1139
- const config = {
1140
- code: urlParams.get("code") || "",
1141
- scope: urlParams.get("scope") || "email",
1142
- state: urlParams.get("state")
1143
- };
1144
- if (!config.code) {
1145
- return;
1140
+ const maybeLowerLocation = (location, at) => {
1141
+ return location.map((item, index) => {
1142
+ if (index === location.length - 1) {
1143
+ return item < at ? item : item - 1;
1146
1144
  }
1147
- localStorage[TINA_AUTH_CONFIG] = JSON.stringify(config);
1148
- }, []);
1145
+ return item;
1146
+ });
1149
1147
  };
1150
- const createClient = ({
1151
- clientId,
1152
- isLocalClient = true,
1153
- branch,
1154
- tinaioConfig
1155
- }) => {
1156
- return isLocalClient ? new LocalClient() : new Client({
1157
- clientId: clientId || "",
1158
- branch: branch || "main",
1159
- tokenStorage: "LOCAL_STORAGE",
1160
- tinaioConfig
1148
+ const matchesAt = (location, at) => {
1149
+ let matches = false;
1150
+ location.map((item, index) => {
1151
+ if (index === location.length - 1) {
1152
+ if (item === at) {
1153
+ matches = true;
1154
+ }
1155
+ }
1161
1156
  });
1157
+ return matches;
1162
1158
  };
1163
- function assertShape(value, yupSchema, errorMessage) {
1164
- const shape = yupSchema(yup__namespace);
1165
- try {
1166
- shape.validateSync(value);
1167
- } catch (e) {
1168
- const message = errorMessage || `Failed to assertShape - ${e.message}`;
1169
- throw new Error(message);
1159
+ const swapLocation = (location, mapping) => {
1160
+ return location.map((item, index) => {
1161
+ if (index === location.length - 1) {
1162
+ return mapping[item];
1163
+ }
1164
+ return item;
1165
+ });
1166
+ };
1167
+ const getSubFields = (changeSet) => {
1168
+ var _a;
1169
+ const fields = changeSet.fieldDefinition.fields ? changeSet.fieldDefinition.fields : changeSet.fieldDefinition.templates[changeSet.value[0]._template].fields;
1170
+ let __typename;
1171
+ if ((_a = changeSet.fieldDefinition) == null ? void 0 : _a.templates) {
1172
+ __typename = changeSet.fieldDefinition.typeMap[changeSet.value[0]._template];
1170
1173
  }
1171
- }
1172
- function safeAssertShape(value, yupSchema) {
1173
- try {
1174
- assertShape(value, yupSchema);
1175
- return true;
1176
- } catch (e) {
1174
+ return { fields, __typename };
1175
+ };
1176
+ const isFormifiableDocument = (t) => {
1177
+ const type = G__namespace.getNamedType(t);
1178
+ if (G__namespace.isUnionType(type)) {
1179
+ return type.getTypes().every((type2) => {
1180
+ return type2.getInterfaces().find((intfc) => intfc.name === "Node");
1181
+ });
1182
+ } else if (G__namespace.isObjectType(type)) {
1183
+ return !!type.getInterfaces().find((intfc) => intfc.name === "Node");
1184
+ } else {
1177
1185
  return false;
1178
1186
  }
1179
- }
1180
- class TinaAdminApi {
1181
- constructor(cms) {
1182
- this.api = cms.api.tina;
1187
+ };
1188
+ const isScalarType = (t) => {
1189
+ const namedType = G__namespace.getNamedType(t);
1190
+ return G__namespace.isScalarType(namedType);
1191
+ };
1192
+ const isConnectionField = (t) => {
1193
+ const type = G__namespace.getNamedType(t);
1194
+ if (G__namespace.isObjectType(type)) {
1195
+ return !!type.getInterfaces().find((intfc) => intfc.name === "Connection");
1196
+ } else {
1197
+ throw new Error(`Expected GraphQLObjectType for isConnectionField check`);
1183
1198
  }
1184
- async isAuthenticated() {
1185
- return await this.api.isAuthenticated();
1199
+ };
1200
+ const getObjectField = (object, selectionNode) => {
1201
+ const namedType = G__namespace.getNamedType(object);
1202
+ ensureObjectOrInterfaceType(namedType);
1203
+ return namedType.getFields()[selectionNode.name.value];
1204
+ };
1205
+ const getSelectedUnionType = (unionType, selectionNode) => {
1206
+ const namedType = G__namespace.getNamedType(unionType);
1207
+ if (!G__namespace.isUnionType(namedType)) {
1208
+ return;
1186
1209
  }
1187
- async fetchCollections() {
1188
- const response = await this.api.request(`#graphql
1189
- query{
1190
- getCollections {
1191
- label,
1192
- name
1193
- }
1194
- }`, { variables: {} });
1195
- return response;
1210
+ const types = namedType.getTypes();
1211
+ const typeCondition = selectionNode.typeCondition.name.value;
1212
+ let intfc;
1213
+ types.forEach((type) => {
1214
+ intfc = type.getInterfaces().find((intfc2) => intfc2.name === typeCondition);
1215
+ });
1216
+ if (intfc) {
1217
+ return intfc;
1196
1218
  }
1197
- async fetchCollection(collectionName, includeDocuments) {
1198
- const response = await this.api.request(`#graphql
1199
- query($collection: String!, $includeDocuments: Boolean!){
1200
- getCollection(collection: $collection){
1201
- name
1202
- label
1203
- format
1204
- templates
1205
- documents @include(if: $includeDocuments) {
1206
- totalCount
1207
- edges {
1208
- node {
1209
- ... on Document {
1210
- sys {
1211
- template
1212
- breadcrumbs
1213
- path
1214
- basename
1215
- relativePath
1216
- filename
1217
- extension
1218
- }
1219
- }
1220
- }
1221
- }
1222
- }
1223
- }
1224
- }`, { variables: { collection: collectionName, includeDocuments } });
1225
- return response;
1219
+ return namedType.getTypes().find((type) => type.name === typeCondition);
1220
+ };
1221
+ function isListType(type) {
1222
+ if (G__namespace.isListType(type)) {
1223
+ return true;
1224
+ } else if (G__namespace.isNonNullType(type)) {
1225
+ if (G__namespace.isListType(type.ofType)) {
1226
+ return true;
1227
+ }
1226
1228
  }
1227
- async fetchDocument(collectionName, relativePath) {
1228
- const response = await this.api.request(`#graphql
1229
- query($collection: String!, $relativePath: String!) {
1230
- getDocument(collection:$collection, relativePath:$relativePath) {
1231
- ... on Document {
1232
- form
1233
- values
1234
- }
1235
- }
1236
- }`, { variables: { collection: collectionName, relativePath } });
1237
- return response;
1238
- }
1239
- async fetchDocumentFields() {
1240
- const response = await this.api.request(`#graphql
1241
- query {
1242
- getDocumentFields
1243
- }`, { variables: {} });
1244
- return response;
1245
- }
1246
- async createDocument(collectionName, relativePath, params) {
1247
- const response = await this.api.request(`#graphql
1248
- mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1249
- createDocument(
1250
- collection: $collection,
1251
- relativePath: $relativePath,
1252
- params: $params
1253
- ){__typename}
1254
- }`, {
1255
- variables: {
1256
- collection: collectionName,
1257
- relativePath,
1258
- params
1259
- }
1260
- });
1261
- return response;
1229
+ return false;
1230
+ }
1231
+ function ensureObjectOrInterfaceType(type) {
1232
+ if (G__namespace.isInterfaceType(type) || G__namespace.isObjectType(type))
1233
+ ;
1234
+ else {
1235
+ console.log("Expected type to be GraphQLObjectType or GraphQLInterfaceType", type);
1236
+ throw new Error(`Expected type to be GraphQLObjectType or GraphQLInterfaceType`);
1262
1237
  }
1263
- async updateDocument(collectionName, relativePath, params) {
1264
- const response = await this.api.request(`#graphql
1265
- mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
1266
- updateDocument(
1267
- collection: $collection,
1268
- relativePath: $relativePath,
1269
- params: $params
1270
- ){__typename}
1271
- }`, {
1272
- variables: {
1273
- collection: collectionName,
1274
- relativePath,
1275
- params
1276
- }
1277
- });
1278
- return response;
1238
+ }
1239
+ function ensureOperationDefinition(type) {
1240
+ if (type.kind !== "OperationDefinition") {
1241
+ throw new Error(`Expected top-level definition to be an OperationDefinition node, ensure your query has been optimized before calling formify`);
1279
1242
  }
1280
1243
  }
1281
- function sleep(ms) {
1282
- return new Promise((resolve) => setTimeout(resolve, ms));
1244
+ function buildPath({
1245
+ fieldNode,
1246
+ type,
1247
+ parentTypename,
1248
+ path
1249
+ }) {
1250
+ const p = path || [];
1251
+ const list = isListType(type);
1252
+ const isNode = isFormifiableDocument(type);
1253
+ return [
1254
+ ...p,
1255
+ {
1256
+ name: fieldNode.name.value,
1257
+ alias: fieldNode.alias ? fieldNode.alias.value : fieldNode.name.value,
1258
+ parentTypename,
1259
+ list: !!list,
1260
+ isNode: !!isNode
1261
+ }
1262
+ ];
1283
1263
  }
1284
- const AuthWallInner = ({
1285
- children,
1286
- cms,
1287
- loginScreen,
1288
- getModalActions
1289
- }) => {
1290
- const client = cms.api.tina;
1291
- const [activeModal, setActiveModal] = React.useState(null);
1292
- const [showChildren, setShowChildren] = React.useState(false);
1293
- React__default["default"].useEffect(() => {
1294
- client.isAuthenticated().then((isAuthenticated) => {
1295
- if (isAuthenticated) {
1296
- setShowChildren(true);
1297
- cms.enable();
1298
- } else {
1299
- sleep(500).then(() => {
1300
- setActiveModal("authenticate");
1301
- });
1264
+ const node = G__namespace.parse(`
1265
+ query Sample {
1266
+ _internalSys: sys {
1267
+ path
1268
+ collection {
1269
+ name
1270
+ }
1271
+ }
1272
+ form
1273
+ values
1274
+ }`);
1275
+ const metaFields = node.definitions[0].selectionSet.selections;
1276
+ const getRelativeBlueprint = (path) => {
1277
+ let indexOfLastNode = 0;
1278
+ path.forEach((item, i) => {
1279
+ if (item.isNode) {
1280
+ if (i === path.length - 1)
1281
+ ;
1282
+ else {
1283
+ indexOfLastNode = i;
1302
1284
  }
1303
- });
1304
- }, []);
1305
- const onAuthSuccess = async () => {
1306
- if (await client.isAuthenticated()) {
1307
- setShowChildren(true);
1308
- setActiveModal(null);
1309
- } else {
1310
- throw new Error("No access to repo");
1311
1285
  }
1312
- };
1313
- const otherModalActions = getModalActions ? getModalActions({
1314
- closeModal: () => {
1315
- setActiveModal(null);
1286
+ });
1287
+ const documentBlueprintPath = path.slice(0, indexOfLastNode + 1);
1288
+ return getBlueprintNamePath({ path: documentBlueprintPath });
1289
+ };
1290
+ const getBlueprintId = (path) => {
1291
+ const namePath = [];
1292
+ const aliasPath = [];
1293
+ path.forEach((p) => {
1294
+ namePath.push(p.name);
1295
+ aliasPath.push(p.alias);
1296
+ if (p.list) {
1297
+ namePath.push("[]");
1298
+ aliasPath.push("[]");
1316
1299
  }
1317
- }) : [];
1318
- return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, activeModal === "authenticate" && /* @__PURE__ */ React__default["default"].createElement(ModalBuilder, {
1319
- title: "Tina Cloud Authorization",
1320
- message: "To save edits, Tina Cloud authorization is required. On save, changes will get commited using your account.",
1321
- close,
1322
- actions: [
1323
- ...otherModalActions,
1324
- {
1325
- action: async () => {
1326
- sharedctx.setEditing(false);
1327
- window.location.reload();
1328
- },
1329
- name: "Close",
1330
- primary: false
1331
- },
1332
- {
1333
- name: "Continue to Tina Cloud",
1334
- action: async () => {
1335
- await client.authenticate();
1336
- onAuthSuccess();
1337
- },
1338
- primary: true
1339
- }
1340
- ]
1341
- }), showChildren ? children : loginScreen ? loginScreen : null);
1300
+ });
1301
+ return namePath.join(".");
1342
1302
  };
1343
- const TinaCloudProvider = (props) => {
1344
- const baseBranch = props.branch || "main";
1345
- const [currentBranch, setCurrentBranch] = toolkit.useLocalStorage("tinacms-current-branch", baseBranch);
1346
- useTinaAuthRedirect();
1347
- const cms = React__default["default"].useMemo(() => props.cms || new toolkit.TinaCMS({
1348
- enabled: true,
1349
- sidebar: true
1350
- }), [props.cms]);
1351
- if (!cms.api.tina) {
1352
- cms.registerApi("tina", createClient(props));
1353
- }
1354
- if (!cms.api.admin) {
1355
- cms.registerApi("admin", new TinaAdminApi(cms));
1356
- }
1357
- const setupMedia = async () => {
1358
- var _a;
1359
- if (props.mediaStore) {
1360
- if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
1361
- cms.media.store = new props.mediaStore(cms.api.tina);
1362
- } else {
1363
- const MediaClass = await props.mediaStore();
1364
- cms.media.store = new MediaClass(cms.api.tina);
1303
+ const NOOP = "This is either an error or is not yet supported";
1304
+ const UNEXPECTED = "Formify encountered an unexpected error, please contact support";
1305
+ const EDGES_NODE_NAME = "edges";
1306
+ const NODE_NAME = "node";
1307
+ const COLLECTION_FIELD_NAME = "getCollection";
1308
+ const COLLECTIONS_FIELD_NAME = "getCollections";
1309
+ const COLLECTIONS_DOCUMENTS_NAME = "documents";
1310
+ const DATA_NODE_NAME = "data";
1311
+ const formify = async ({
1312
+ schema,
1313
+ query,
1314
+ getOptimizedQuery
1315
+ }) => {
1316
+ const blueprints = [];
1317
+ const documentNode = G__namespace.parse(query);
1318
+ const visitor = {
1319
+ OperationDefinition: (node2) => {
1320
+ if (!node2.name) {
1321
+ return __spreadProps(__spreadValues({}, node2), {
1322
+ name: {
1323
+ kind: "Name",
1324
+ value: `QueryOperation`
1325
+ }
1326
+ });
1365
1327
  }
1328
+ return node2;
1366
1329
  }
1367
1330
  };
1368
- const handleListBranches = async () => {
1369
- const { owner, repo } = props;
1370
- const branches = await cms.api.tina.listBranches({ owner, repo });
1371
- if (!Array.isArray(branches)) {
1372
- return [];
1373
- }
1374
- return branches;
1375
- };
1376
- const handleCreateBranch = async (data) => {
1377
- const newBranch = await cms.api.tina.createBranch(data);
1378
- return newBranch;
1331
+ const documentNodeWithName = G__namespace.visit(documentNode, visitor);
1332
+ const optimizedQuery = await getOptimizedQuery(documentNodeWithName);
1333
+ const typeInfo = new G__namespace.TypeInfo(schema);
1334
+ const formifyConnection = ({
1335
+ parentType,
1336
+ selectionNode,
1337
+ path
1338
+ }) => {
1339
+ return __spreadProps(__spreadValues({}, selectionNode), {
1340
+ selectionSet: {
1341
+ kind: "SelectionSet",
1342
+ selections: selectionNode.selectionSet.selections.map((selectionNode2) => {
1343
+ switch (selectionNode2.kind) {
1344
+ case "Field":
1345
+ if (selectionNode2.name.value === EDGES_NODE_NAME) {
1346
+ const edgeField = getObjectField(parentType, selectionNode2);
1347
+ const edgesPath = buildPath({
1348
+ fieldNode: selectionNode2,
1349
+ type: edgeField.type,
1350
+ path
1351
+ });
1352
+ return __spreadProps(__spreadValues({}, selectionNode2), {
1353
+ selectionSet: {
1354
+ kind: "SelectionSet",
1355
+ selections: selectionNode2.selectionSet.selections.map((subSelectionNode) => {
1356
+ switch (subSelectionNode.kind) {
1357
+ case "Field":
1358
+ if (subSelectionNode.name.value === NODE_NAME) {
1359
+ const nodeField = getObjectField(edgeField.type, subSelectionNode);
1360
+ return formifyFieldNodeDocument({
1361
+ fieldNode: subSelectionNode,
1362
+ type: nodeField.type,
1363
+ path: buildPath({
1364
+ fieldNode: subSelectionNode,
1365
+ type: nodeField.type,
1366
+ path: edgesPath
1367
+ }),
1368
+ showInSidebar: false
1369
+ });
1370
+ } else {
1371
+ return subSelectionNode;
1372
+ }
1373
+ default:
1374
+ throw new FormifyError("NOOP");
1375
+ }
1376
+ })
1377
+ }
1378
+ });
1379
+ }
1380
+ return selectionNode2;
1381
+ default:
1382
+ throw new FormifyError("UNEXPECTED");
1383
+ }
1384
+ })
1385
+ }
1386
+ });
1379
1387
  };
1380
- setupMedia();
1381
- const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
1382
- React__default["default"].useEffect(() => {
1383
- cms.events.subscribe("flag:set", ({ key, value }) => {
1384
- if (key === "branch-switcher") {
1385
- setBranchingEnabled(value);
1388
+ function formifyInlineFragmentDocument({
1389
+ inlineFragmentNode,
1390
+ type,
1391
+ path,
1392
+ showInSidebar = false
1393
+ }) {
1394
+ return formifyDocument({
1395
+ selection: inlineFragmentNode,
1396
+ type,
1397
+ path,
1398
+ showInSidebar
1399
+ });
1400
+ }
1401
+ function formifyFieldNodeDocument({
1402
+ fieldNode,
1403
+ type,
1404
+ path,
1405
+ showInSidebar = false
1406
+ }) {
1407
+ return formifyDocument({ selection: fieldNode, type, path, showInSidebar });
1408
+ }
1409
+ function formifyDocument({
1410
+ selection,
1411
+ type,
1412
+ path,
1413
+ showInSidebar = false
1414
+ }) {
1415
+ let extraFields = [];
1416
+ let hasDataJSONField = false;
1417
+ let hasValuesField = false;
1418
+ let shouldFormify = false;
1419
+ selection.selectionSet.selections.forEach((selection2) => {
1420
+ if (selection2.kind === "Field") {
1421
+ if (selection2.name.value === "dataJSON") {
1422
+ shouldFormify = true;
1423
+ hasDataJSONField = true;
1424
+ }
1425
+ if (selection2.name.value === "values") {
1426
+ shouldFormify = true;
1427
+ hasValuesField = true;
1428
+ }
1429
+ if (selection2.name.value === "data") {
1430
+ shouldFormify = true;
1431
+ }
1386
1432
  }
1387
1433
  });
1388
- }, [cms.events]);
1389
- React__default["default"].useEffect(() => {
1390
- let branchSwitcher;
1391
- if (branchingEnabled) {
1392
- branchSwitcher = new toolkit.BranchSwitcherPlugin({
1393
- listBranches: handleListBranches,
1394
- createBranch: handleCreateBranch
1434
+ if (shouldFormify) {
1435
+ blueprints.push({
1436
+ id: getBlueprintId(path),
1437
+ path,
1438
+ selection,
1439
+ fields: [],
1440
+ showInSidebar,
1441
+ hasDataJSONField,
1442
+ hasValuesField
1395
1443
  });
1396
- cms.plugins.add(branchSwitcher);
1444
+ extraFields = metaFields;
1397
1445
  }
1398
- return () => {
1399
- if (branchingEnabled && branchSwitcher) {
1400
- cms.plugins.remove(branchSwitcher);
1446
+ return __spreadProps(__spreadValues({}, selection), {
1447
+ selectionSet: {
1448
+ kind: "SelectionSet",
1449
+ selections: [
1450
+ ...selection.selectionSet.selections.map((selectionNode) => {
1451
+ switch (selectionNode.kind) {
1452
+ case "InlineFragment": {
1453
+ const namedType = G__namespace.getNamedType(type);
1454
+ if (G__namespace.isInterfaceType(namedType)) {
1455
+ const subType = schema.getImplementations(namedType).objects.find((item) => item.name === selectionNode.typeCondition.name.value);
1456
+ return formifyInlineFragmentDocument({
1457
+ inlineFragmentNode: selectionNode,
1458
+ type: subType,
1459
+ path,
1460
+ showInSidebar: true
1461
+ });
1462
+ }
1463
+ return formifyInlineFragmentNode({
1464
+ inlineFragmentNode: selectionNode,
1465
+ parentType: type,
1466
+ path
1467
+ });
1468
+ }
1469
+ case "Field": {
1470
+ if (selectionNode.name.value === DATA_NODE_NAME) {
1471
+ const field = getObjectField(type, selectionNode);
1472
+ return __spreadProps(__spreadValues({}, selectionNode), {
1473
+ selectionSet: {
1474
+ kind: "SelectionSet",
1475
+ selections: [
1476
+ ...selectionNode.selectionSet.selections.map((subSelectionNode) => {
1477
+ switch (subSelectionNode.kind) {
1478
+ case "Field":
1479
+ return formifyFieldNode({
1480
+ fieldNode: subSelectionNode,
1481
+ parentType: field.type,
1482
+ path: buildPath({
1483
+ fieldNode: selectionNode,
1484
+ type: field.type,
1485
+ path
1486
+ })
1487
+ });
1488
+ default:
1489
+ throw new FormifyError("UNEXPECTED", `selection ${subSelectionNode.kind}`);
1490
+ }
1491
+ })
1492
+ ]
1493
+ }
1494
+ });
1495
+ }
1496
+ return selectionNode;
1497
+ }
1498
+ default:
1499
+ throw new FormifyError("UNEXPECTED");
1500
+ }
1501
+ }),
1502
+ ...extraFields
1503
+ ]
1401
1504
  }
1402
- };
1403
- }, [branchingEnabled, props.branch]);
1404
- React__default["default"].useEffect(() => {
1405
- if (props.cmsCallback) {
1406
- props.cmsCallback(cms);
1505
+ });
1506
+ }
1507
+ const formifyFieldNode = ({
1508
+ fieldNode,
1509
+ parentType,
1510
+ path
1511
+ }) => {
1512
+ if (fieldNode.name.value === "__typename") {
1513
+ return fieldNode;
1407
1514
  }
1408
- }, []);
1409
- return /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchDataProvider, {
1410
- currentBranch,
1411
- setCurrentBranch: (b) => {
1412
- setCurrentBranch(b);
1515
+ const field = getObjectField(parentType, fieldNode);
1516
+ if (!field) {
1517
+ return fieldNode;
1413
1518
  }
1414
- }, /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
1415
- cms
1416
- }, /* @__PURE__ */ React__default["default"].createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
1417
- cms
1418
- }))));
1419
- };
1420
- const TinaCloudAuthWall = TinaCloudProvider;
1421
- function useGraphqlForms({
1422
- variables,
1423
- onSubmit,
1424
- formify: formify2 = null,
1425
- query
1426
- }) {
1427
- const cms = toolkit.useCMS();
1428
- const [formValues, setFormValues] = React__default["default"].useState({});
1429
- const [data, setData] = React__default["default"].useState(null);
1430
- const [initialData, setInitialData] = React__default["default"].useState({});
1431
- const [pendingReset, setPendingReset] = React__default["default"].useState(null);
1432
- const [isLoading, setIsLoading] = React__default["default"].useState(true);
1433
- const [newUpdate, setNewUpdate] = React__default["default"].useState(null);
1434
- const { currentBranch } = toolkit.useBranchData();
1435
- const updateData = async () => {
1436
- var _a;
1437
- if (newUpdate) {
1438
- const newValue = finalForm.getIn(formValues, newUpdate.get);
1439
- const activeForm = finalForm.getIn(data, [newUpdate.queryName, "form"].join("."));
1440
- if (!activeForm) {
1441
- throw new Error(`Unable to find form for query ${newUpdate.queryName}`);
1519
+ const blueprint = blueprints.find((blueprint2) => blueprint2.id === getRelativeBlueprint(path));
1520
+ if (!blueprint) {
1521
+ return fieldNode;
1522
+ }
1523
+ const fieldPath = buildPath({
1524
+ fieldNode,
1525
+ type: field.type,
1526
+ parentTypename: G__namespace.getNamedType(parentType).name,
1527
+ path
1528
+ });
1529
+ blueprint.fields.push({
1530
+ id: getBlueprintId(fieldPath),
1531
+ documentBlueprintId: blueprint.id,
1532
+ path: fieldPath
1533
+ });
1534
+ if (isScalarType(field.type)) {
1535
+ return fieldNode;
1536
+ }
1537
+ return __spreadProps(__spreadValues({}, fieldNode), {
1538
+ selectionSet: {
1539
+ kind: "SelectionSet",
1540
+ selections: [
1541
+ ...fieldNode.selectionSet.selections.map((selectionNode) => {
1542
+ switch (selectionNode.kind) {
1543
+ case "Field": {
1544
+ return formifyFieldNode({
1545
+ fieldNode: selectionNode,
1546
+ parentType: field.type,
1547
+ path: fieldPath
1548
+ });
1549
+ }
1550
+ case "InlineFragment": {
1551
+ return formifyInlineFragmentNode({
1552
+ inlineFragmentNode: selectionNode,
1553
+ parentType: field.type,
1554
+ path: fieldPath
1555
+ });
1556
+ }
1557
+ default:
1558
+ throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
1559
+ }
1560
+ })
1561
+ ]
1442
1562
  }
1443
- if (activeForm == null ? void 0 : activeForm.paths) {
1444
- const asyncUpdate = (_a = activeForm.paths) == null ? void 0 : _a.find((p) => p.dataPath.join(".") === newUpdate.setReference);
1445
- if (asyncUpdate) {
1446
- const res = await cms.api.tina.request(asyncUpdate.queryString, {
1447
- variables: { id: newValue }
1448
- });
1449
- const newData2 = finalForm.setIn(data, newUpdate.set, res.node);
1450
- const newDataAndNewJSONData2 = finalForm.setIn(newData2, newUpdate.set.replace("data", "dataJSON"), newValue);
1451
- setData(newDataAndNewJSONData2);
1452
- setNewUpdate(null);
1453
- return;
1563
+ });
1564
+ };
1565
+ const formifyInlineFragmentNode = ({
1566
+ inlineFragmentNode,
1567
+ parentType,
1568
+ path
1569
+ }) => {
1570
+ const type = getSelectedUnionType(parentType, inlineFragmentNode);
1571
+ if (!type) {
1572
+ return inlineFragmentNode;
1573
+ }
1574
+ if (isFormifiableDocument(type)) {
1575
+ return formifyInlineFragmentDocument({
1576
+ inlineFragmentNode,
1577
+ type,
1578
+ path,
1579
+ showInSidebar: false
1580
+ });
1581
+ }
1582
+ return __spreadProps(__spreadValues({}, inlineFragmentNode), {
1583
+ selectionSet: {
1584
+ kind: "SelectionSet",
1585
+ selections: inlineFragmentNode.selectionSet.selections.map((selectionNode) => {
1586
+ switch (selectionNode.kind) {
1587
+ case "Field":
1588
+ return formifyFieldNode({
1589
+ fieldNode: selectionNode,
1590
+ parentType: type,
1591
+ path
1592
+ });
1593
+ default:
1594
+ throw new FormifyError("UNEXPECTED", `selection ${selectionNode.kind}`);
1595
+ }
1596
+ })
1597
+ }
1598
+ });
1599
+ };
1600
+ const formifiedQuery = {
1601
+ kind: "Document",
1602
+ definitions: optimizedQuery.definitions.map((definition) => {
1603
+ typeInfo.enter(definition);
1604
+ ensureOperationDefinition(definition);
1605
+ const parentType = typeInfo.getType();
1606
+ return __spreadProps(__spreadValues({}, definition), {
1607
+ selectionSet: {
1608
+ kind: "SelectionSet",
1609
+ selections: definition.selectionSet.selections.map((selectionNode) => {
1610
+ switch (selectionNode.kind) {
1611
+ case "Field":
1612
+ const field = getObjectField(parentType, selectionNode);
1613
+ const path = buildPath({
1614
+ fieldNode: selectionNode,
1615
+ type: field.type
1616
+ });
1617
+ if (isFormifiableDocument(field.type)) {
1618
+ return formifyFieldNodeDocument({
1619
+ fieldNode: selectionNode,
1620
+ type: field.type,
1621
+ path,
1622
+ showInSidebar: true
1623
+ });
1624
+ } else if (isConnectionField(field.type)) {
1625
+ return formifyConnection({
1626
+ parentType: field.type,
1627
+ selectionNode,
1628
+ path
1629
+ });
1630
+ }
1631
+ if (selectionNode.name.value === COLLECTION_FIELD_NAME || selectionNode.name.value === COLLECTIONS_FIELD_NAME) {
1632
+ const path2 = buildPath({
1633
+ fieldNode: selectionNode,
1634
+ type: field.type
1635
+ });
1636
+ return __spreadProps(__spreadValues({}, selectionNode), {
1637
+ selectionSet: {
1638
+ kind: "SelectionSet",
1639
+ selections: selectionNode.selectionSet.selections.map((subSelectionNode) => {
1640
+ switch (subSelectionNode.kind) {
1641
+ case "Field":
1642
+ if (subSelectionNode.name.value === COLLECTIONS_DOCUMENTS_NAME) {
1643
+ const subField = getObjectField(field.type, subSelectionNode);
1644
+ return formifyConnection({
1645
+ parentType: subField.type,
1646
+ selectionNode: subSelectionNode,
1647
+ path: buildPath({
1648
+ fieldNode: subSelectionNode,
1649
+ type: subField.type,
1650
+ path: path2
1651
+ })
1652
+ });
1653
+ }
1654
+ return subSelectionNode;
1655
+ default:
1656
+ throw new FormifyError("NOOP");
1657
+ }
1658
+ })
1659
+ }
1660
+ });
1661
+ }
1662
+ throw new FormifyError("NOOP");
1663
+ default:
1664
+ throw new FormifyError("UNEXPECTED");
1665
+ }
1666
+ })
1454
1667
  }
1668
+ });
1669
+ })
1670
+ };
1671
+ return { formifiedQuery, blueprints };
1672
+ };
1673
+ class FormifyError extends Error {
1674
+ constructor(code, details) {
1675
+ let message;
1676
+ switch (code) {
1677
+ case "NOOP":
1678
+ message = NOOP;
1679
+ break;
1680
+ case "UNEXPECTED":
1681
+ message = UNEXPECTED;
1682
+ break;
1683
+ default:
1684
+ message = "";
1685
+ break;
1686
+ }
1687
+ super(`${message} ${details || ""}`);
1688
+ this.name = "FormifyError";
1689
+ }
1690
+ }
1691
+ const defaultState = {
1692
+ status: "idle",
1693
+ schema: void 0,
1694
+ query: null,
1695
+ queryString: null,
1696
+ data: {},
1697
+ changeSets: [],
1698
+ count: 0,
1699
+ blueprints: [],
1700
+ formNodes: [],
1701
+ documentForms: []
1702
+ };
1703
+ function reducer(state, action) {
1704
+ var _a, _b, _c, _d;
1705
+ switch (action.type) {
1706
+ case "start":
1707
+ return __spreadProps(__spreadValues(__spreadValues({}, state), defaultState), {
1708
+ query: action.value.query ? G__namespace.parse(action.value.query) : null,
1709
+ queryString: action.value.query,
1710
+ status: "initialized"
1711
+ });
1712
+ case "addDocumentBlueprints":
1713
+ return __spreadProps(__spreadValues({}, state), {
1714
+ status: "formified",
1715
+ blueprints: action.value.blueprints,
1716
+ query: action.value.formifiedQuery
1717
+ });
1718
+ case "addOrReplaceDocumentFormNode": {
1719
+ const existingDocumentForms = state.documentForms.filter((documentForm) => {
1720
+ var _a2, _b2;
1721
+ return documentForm.id !== ((_b2 = (_a2 = action.value) == null ? void 0 : _a2.documentForm) == null ? void 0 : _b2.id);
1722
+ });
1723
+ const existingDocumentFormNodes = state.formNodes.filter((formNode) => {
1724
+ return formNodeId(formNode) !== formNodeId(action.value.formNode);
1725
+ });
1726
+ const newDocumentForms = [];
1727
+ if ((_a = action.value) == null ? void 0 : _a.documentForm) {
1728
+ newDocumentForms.push((_b = action.value) == null ? void 0 : _b.documentForm);
1455
1729
  }
1456
- if (newUpdate.lookup) {
1457
- const field = getFieldUpdate(newUpdate, activeForm, formValues);
1458
- if (field && field.typeMap) {
1459
- newValue.forEach((item) => {
1460
- if (!item.__typename) {
1461
- item["__typename"] = field.typeMap[item._template];
1730
+ return __spreadProps(__spreadValues({}, state), {
1731
+ formNodes: [...existingDocumentFormNodes, action.value.formNode],
1732
+ documentForms: [...existingDocumentForms, ...newDocumentForms]
1733
+ });
1734
+ }
1735
+ case "onFieldChange": {
1736
+ const event = action.value.event;
1737
+ const changeSets = [];
1738
+ const formNodesToReplace = [];
1739
+ const formNodesToRemove = [];
1740
+ const newFormNodes = [];
1741
+ const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1742
+ getFormNodesFromEvent(state, event).forEach((formNode) => {
1743
+ const blueprint = getFormNodeBlueprint(formNode, state);
1744
+ if (blueprint.hasValuesField) {
1745
+ changeSets.push(__spreadProps(__spreadValues({
1746
+ path: [formNodePath(formNode), "values"].join(".")
1747
+ }, buildChangeSet(event, formNode)), {
1748
+ value: form.values,
1749
+ mutationType: {
1750
+ type: "global"
1751
+ }
1752
+ }));
1753
+ }
1754
+ if (blueprint.hasDataJSONField) {
1755
+ changeSets.push(__spreadProps(__spreadValues({
1756
+ path: [formNodePath(formNode), "dataJSON"].join(".")
1757
+ }, buildChangeSet(event, formNode)), {
1758
+ value: form.values,
1759
+ mutationType: {
1760
+ type: "global"
1761
+ }
1762
+ }));
1763
+ }
1764
+ if (event.mutationType.type === "change") {
1765
+ if (!action.value.form) {
1766
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1767
+ const { pathToChange } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1768
+ changeSets.push(__spreadValues({
1769
+ path: pathToChange
1770
+ }, buildChangeSet(event, formNode)));
1771
+ });
1772
+ }
1773
+ } else if (event.mutationType.type === "referenceChange") {
1774
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1775
+ const {
1776
+ pathToChange,
1777
+ formNodes: subFormNodes,
1778
+ eventLocation
1779
+ } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1780
+ if (action.value.form && state.blueprints.find((blueprint2) => blueprint2.id === fieldBlueprint.id)) {
1781
+ const newFormNode = {
1782
+ documentBlueprintId: fieldBlueprint.id,
1783
+ documentFormId: action.value.form.id,
1784
+ location: eventLocation
1785
+ };
1786
+ newFormNodes.push(newFormNode);
1787
+ changeSets.push(__spreadValues({
1788
+ path: pathToChange
1789
+ }, buildChangeSet(event, newFormNode)));
1790
+ }
1791
+ subFormNodes.forEach((subFormNode) => {
1792
+ if (matchLocation(eventLocation, subFormNode)) {
1793
+ if (!action.value.form) {
1794
+ changeSets.push(__spreadProps(__spreadValues({
1795
+ path: pathToChange
1796
+ }, buildChangeSet(event, subFormNode)), {
1797
+ value: null
1798
+ }));
1799
+ }
1800
+ formNodesToReplace.push(subFormNode);
1801
+ }
1802
+ });
1803
+ });
1804
+ } else {
1805
+ getBlueprintFieldsForEvent(blueprint, event).forEach((fieldBlueprint) => {
1806
+ const { pathToChange, formNodes, existing, eventLocation } = getFormNodesForField(fieldBlueprint, formNode, event, state);
1807
+ if (event.mutationType.type === "insert") {
1808
+ formNodes.forEach((subFormNode) => {
1809
+ if (matchLocation(eventLocation, subFormNode)) {
1810
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1811
+ location: bumpLocation(subFormNode.location)
1812
+ }));
1813
+ formNodesToReplace.push(subFormNode);
1814
+ }
1815
+ });
1816
+ changeSets.push(__spreadValues({
1817
+ path: pathToChange
1818
+ }, buildChangeSet(event, formNode)));
1819
+ }
1820
+ if (event.mutationType.type === "remove") {
1821
+ const { at } = event.mutationType;
1822
+ formNodes.forEach((subFormNode) => {
1823
+ if (matchLocation(eventLocation, subFormNode)) {
1824
+ if (matchesAt(subFormNode.location, at)) {
1825
+ formNodesToRemove.push(subFormNode);
1826
+ } else {
1827
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1828
+ location: maybeLowerLocation(subFormNode.location, at)
1829
+ }));
1830
+ formNodesToReplace.push(subFormNode);
1831
+ }
1832
+ }
1833
+ });
1834
+ const next = existing.filter((_, index) => index !== at);
1835
+ changeSets.push(__spreadProps(__spreadValues({
1836
+ path: pathToChange
1837
+ }, buildChangeSet(event, formNode)), {
1838
+ value: next
1839
+ }));
1840
+ }
1841
+ if (event.mutationType.type === "move") {
1842
+ const next = [];
1843
+ const { from, to } = event.mutationType;
1844
+ const newOrderObject = getMoveMapping(existing, from, to);
1845
+ formNodes.forEach((subFormNode) => {
1846
+ if (matchLocation(eventLocation, subFormNode)) {
1847
+ newFormNodes.push(__spreadProps(__spreadValues({}, subFormNode), {
1848
+ location: swapLocation(subFormNode.location, newOrderObject)
1849
+ }));
1850
+ formNodesToReplace.push(subFormNode);
1851
+ }
1852
+ });
1853
+ Object.values(newOrderObject).forEach((orderIndex, index) => {
1854
+ next[orderIndex] = existing[index];
1855
+ });
1856
+ changeSets.push(__spreadProps(__spreadValues({
1857
+ path: pathToChange
1858
+ }, buildChangeSet(event, formNode)), {
1859
+ value: next
1860
+ }));
1462
1861
  }
1463
1862
  });
1464
1863
  }
1864
+ });
1865
+ const existingDocumentForms = state.documentForms.filter((documentForm) => {
1866
+ var _a2;
1867
+ return documentForm.id !== ((_a2 = action.value.form) == null ? void 0 : _a2.id);
1868
+ });
1869
+ const newDocumentForms = [];
1870
+ if ((_c = action.value) == null ? void 0 : _c.form) {
1871
+ newDocumentForms.push((_d = action.value) == null ? void 0 : _d.form);
1465
1872
  }
1466
- const newData = finalForm.setIn(data, newUpdate.set, newValue);
1467
- const newDataAndNewJSONData = finalForm.setIn(newData, newUpdate.set.replace("data", "dataJSON"), newValue);
1468
- setData(newDataAndNewJSONData);
1469
- setNewUpdate(null);
1873
+ return __spreadProps(__spreadValues({}, state), {
1874
+ changeSets,
1875
+ formNodes: [
1876
+ ...state.formNodes.filter((formNode) => formNodeNotIn(formNode, formNodesToReplace)).filter((formNode) => formNodeNotIn(formNode, formNodesToRemove)),
1877
+ ...newFormNodes
1878
+ ],
1879
+ documentForms: [...existingDocumentForms, ...newDocumentForms]
1880
+ });
1881
+ }
1882
+ case "formOnReset": {
1883
+ const { event } = action.value;
1884
+ const changeSets = [];
1885
+ const form = state.documentForms.find((documentForm) => documentForm.id === event.formId);
1886
+ state.formNodes.filter((fn) => fn.documentFormId === (form == null ? void 0 : form.id)).forEach((formNode) => {
1887
+ const blueprint = getFormNodeBlueprint(formNode, state);
1888
+ if (blueprint.hasValuesField) {
1889
+ changeSets.push(__spreadValues({
1890
+ path: [formNodePath(formNode), "values"].join(".")
1891
+ }, buildChangeSet(event, formNode)));
1892
+ }
1893
+ if (blueprint.hasDataJSONField) {
1894
+ changeSets.push(__spreadValues({
1895
+ path: [formNodePath(formNode), "dataJSON"].join(".")
1896
+ }, buildChangeSet(event, formNode)));
1897
+ }
1898
+ changeSets.push(__spreadValues({
1899
+ path: [formNodePath(formNode), "data"].join(".")
1900
+ }, buildChangeSet(event, formNode)));
1901
+ });
1902
+ return __spreadProps(__spreadValues({}, state), { changeSets });
1903
+ }
1904
+ case "ready":
1905
+ return __spreadProps(__spreadValues({}, state), { status: "ready" });
1906
+ case "done":
1907
+ return __spreadProps(__spreadValues({}, state), { status: "done" });
1908
+ case "setData":
1909
+ return __spreadProps(__spreadValues({}, state), { data: action.value });
1910
+ case "setIn": {
1911
+ let newData;
1912
+ if (action.value.displaceIndex) {
1913
+ const existing = finalForm.getIn(state.data, action.value.path) || [];
1914
+ newData = finalForm.setIn(state.data, action.value.path, [
1915
+ action.value.value,
1916
+ ...existing
1917
+ ]);
1918
+ } else {
1919
+ newData = finalForm.setIn(state.data, action.value.path, action.value.value);
1920
+ }
1921
+ const changeSets = state.changeSets.filter((cs) => cs.path !== action.value.path);
1922
+ return __spreadProps(__spreadValues({}, state), {
1923
+ data: newData,
1924
+ changeSets
1925
+ });
1470
1926
  }
1927
+ default:
1928
+ return state;
1929
+ }
1930
+ }
1931
+ const buildChangeSet = (event, formNode) => {
1932
+ var _a, _b, _c;
1933
+ return {
1934
+ fieldDefinition: (_b = (_a = event.field) == null ? void 0 : _a.data) == null ? void 0 : _b.tinaField,
1935
+ name: (_c = event.field) == null ? void 0 : _c.name,
1936
+ formId: event.formId,
1937
+ mutationType: event.mutationType,
1938
+ value: event.value,
1939
+ formNode
1471
1940
  };
1941
+ };
1942
+ const useFormify = ({
1943
+ query,
1944
+ cms,
1945
+ variables,
1946
+ onSubmit,
1947
+ formify: formifyFunc,
1948
+ eventList
1949
+ }) => {
1950
+ const formIds = React__default["default"].useRef([]);
1951
+ const [state, dispatch] = React__default["default"].useReducer(reducer, {
1952
+ status: "idle",
1953
+ schema: void 0,
1954
+ query: query ? G__namespace.parse(query) : null,
1955
+ queryString: query,
1956
+ data: {},
1957
+ changeSets: [],
1958
+ count: 0,
1959
+ blueprints: [],
1960
+ formNodes: [],
1961
+ documentForms: []
1962
+ });
1472
1963
  React__default["default"].useEffect(() => {
1473
- updateData();
1474
- }, [JSON.stringify(formValues)]);
1964
+ if (query) {
1965
+ dispatch({ type: "start", value: { query } });
1966
+ formIds.current.forEach((formId) => {
1967
+ const form = cms.forms.find(formId);
1968
+ if (form) {
1969
+ cms.plugins.remove(form);
1970
+ }
1971
+ });
1972
+ }
1973
+ }, [query, JSON.stringify(variables)]);
1475
1974
  React__default["default"].useEffect(() => {
1476
- if (pendingReset) {
1477
- setData(__spreadProps(__spreadValues({}, data), { [pendingReset]: initialData[pendingReset] }));
1478
- setPendingReset(null);
1975
+ if (state.status === "initialized") {
1976
+ cms.api.tina.request(query, { variables }).then((res) => {
1977
+ delete res.paths;
1978
+ dispatch({ type: "setData", value: res });
1979
+ });
1479
1980
  }
1480
- }, [pendingReset]);
1981
+ }, [state.status]);
1481
1982
  React__default["default"].useEffect(() => {
1482
- if (!query) {
1483
- setIsLoading(false);
1484
- return;
1983
+ const run = async () => {
1984
+ const schema = await cms.api.tina.getSchema();
1985
+ const result = await formify({
1986
+ schema,
1987
+ query,
1988
+ getOptimizedQuery: cms.api.tina.getOptimizedQuery
1989
+ });
1990
+ dispatch({
1991
+ type: "addDocumentBlueprints",
1992
+ value: result
1993
+ });
1994
+ };
1995
+ if (state.status === "initialized") {
1996
+ run();
1485
1997
  }
1486
- const formIds = [];
1487
- setIsLoading(true);
1488
- cms.api.tina.requestWithForm((gql2) => gql2(query), {
1489
- variables,
1490
- useUnstableFormify: cms.flags.get("use-unstable-formify")
1491
- }).then((payload) => {
1492
- cms.plugins.remove(new toolkit.FormMetaPlugin({ name: "tina-admin-link" }));
1493
- setData(payload);
1494
- setInitialData(payload);
1495
- setIsLoading(false);
1496
- Object.entries(payload).map(([queryName, result]) => {
1497
- formIds.push(queryName);
1498
- const canBeFormified = safeAssertShape(result, (yup2) => yup2.object({
1499
- values: yup2.object().required(),
1500
- form: yup2.object().required()
1501
- }));
1502
- if (!canBeFormified) {
1503
- return;
1504
- }
1505
- assertShape(result, (yup2) => yup2.object({
1506
- values: yup2.object().required(),
1507
- form: yup2.object().required()
1508
- }), `Unable to build form shape for fields at ${queryName}`);
1509
- const formConfig = {
1510
- id: queryName,
1511
- label: result.form.label,
1512
- initialValues: result.values,
1513
- fields: result.form.fields,
1514
- reset: () => {
1515
- setPendingReset(queryName);
1516
- },
1517
- onSubmit: async (payload2) => {
1518
- try {
1519
- const params = transformDocumentIntoMutationRequestPayload(payload2, result.form.mutationInfo);
1520
- const variables2 = { params };
1521
- const mutationString = result.form.mutationInfo.string;
1522
- if (onSubmit) {
1523
- onSubmit({
1524
- queryString: mutationString,
1525
- mutationString,
1526
- variables: variables2
1527
- });
1998
+ }, [state.status]);
1999
+ React__default["default"].useEffect(() => {
2000
+ const run = async () => {
2001
+ const result = await cms.api.tina.request(G__namespace.print(state.query), {
2002
+ variables
2003
+ });
2004
+ state.blueprints.map((blueprint) => {
2005
+ const responseAtBlueprint = getValueForBlueprint(result, getBlueprintAliasPath(blueprint));
2006
+ const location = [];
2007
+ const findFormNodes = (res, location2) => {
2008
+ if (Array.isArray(res)) {
2009
+ res.forEach((item, index) => {
2010
+ if (Array.isArray(item)) {
2011
+ findFormNodes(item, [...location2, index]);
1528
2012
  } else {
1529
- try {
1530
- await cms.api.tina.request(mutationString, {
1531
- variables: variables2
2013
+ if (item) {
2014
+ const form = buildForm(item, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
2015
+ const formNode = buildFormNode(blueprint, form, [
2016
+ ...location2,
2017
+ index
2018
+ ]);
2019
+ dispatch({
2020
+ type: "addOrReplaceDocumentFormNode",
2021
+ value: {
2022
+ formNode,
2023
+ documentForm: form
2024
+ }
1532
2025
  });
1533
- cms.alerts.success("Document saved!");
1534
- } catch (e) {
1535
- cms.alerts.error("There was a problem saving your document");
1536
- console.error(e);
1537
2026
  }
1538
2027
  }
1539
- } catch (e) {
1540
- console.error(e);
1541
- cms.alerts.error("There was a problem saving your document");
2028
+ });
2029
+ } else {
2030
+ if (res) {
2031
+ const form = buildForm(res, cms, formifyFunc, blueprint.showInSidebar, onSubmit);
2032
+ const formNode = buildFormNode(blueprint, form, location2);
2033
+ dispatch({
2034
+ type: "addOrReplaceDocumentFormNode",
2035
+ value: {
2036
+ formNode,
2037
+ documentForm: form
2038
+ }
2039
+ });
1542
2040
  }
1543
2041
  }
1544
2042
  };
1545
- const { createForm, createGlobalForm } = generateFormCreators(cms);
1546
- const SKIPPED = "SKIPPED";
1547
- let form;
1548
- let skipped;
1549
- const skip = () => {
1550
- skipped = SKIPPED;
1551
- };
1552
- if (skipped)
1553
- return;
1554
- if (formify2) {
1555
- form = formify2({ formConfig, createForm, createGlobalForm, skip }, cms);
1556
- } else {
1557
- form = createForm(formConfig);
2043
+ findFormNodes(responseAtBlueprint, location);
2044
+ });
2045
+ dispatch({ type: "ready" });
2046
+ };
2047
+ if (state.status === "formified") {
2048
+ run();
2049
+ }
2050
+ }, [state.status]);
2051
+ React__default["default"].useEffect(() => {
2052
+ if (state.status === "ready") {
2053
+ cms.events.subscribe(`forms:reset`, (event) => {
2054
+ if (eventList) {
2055
+ eventList.push(printEvent(event));
1558
2056
  }
1559
- if (!(form instanceof toolkit.Form)) {
1560
- if (skipped === SKIPPED) {
1561
- return;
1562
- }
1563
- throw new Error("formify must return a form or skip()");
2057
+ dispatch({ type: "formOnReset", value: { event } });
2058
+ });
2059
+ cms.events.subscribe(`forms:fields:onChange`, async (event) => {
2060
+ if (eventList) {
2061
+ eventList.push(printEvent(event));
1564
2062
  }
1565
- const { change } = form.finalForm;
1566
- form.finalForm.change = (name, value) => {
1567
- let referenceName = "";
1568
- if (typeof name === "string") {
1569
- referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
1570
- } else {
1571
- throw new Error(`Expected name to be of type string for FinalForm change callback`);
2063
+ if (event.field.data.tinaField.type === "reference") {
2064
+ let form;
2065
+ if (event.value && typeof event.value === "string") {
2066
+ const existingForm = cms.forms.find(event.value);
2067
+ if (existingForm) {
2068
+ form = existingForm;
2069
+ } else {
2070
+ const formInfo = await cms.api.tina.request(`#graphql
2071
+ query Node($id: String!) {
2072
+ node(id: $id) {
2073
+ ...on Document {
2074
+ form
2075
+ values
2076
+ _internalSys: sys {
2077
+ path
2078
+ collection {
2079
+ name
2080
+ }
2081
+ }
2082
+ }
2083
+ }
2084
+ }
2085
+ `, { variables: { id: event.value } });
2086
+ form = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
2087
+ }
1572
2088
  }
1573
- setNewUpdate({
1574
- queryName,
1575
- get: [queryName, "values", name].join("."),
1576
- set: [queryName, "data", name].join("."),
1577
- setReference: [queryName, "data", referenceName].join(".")
2089
+ dispatch({
2090
+ type: "onFieldChange",
2091
+ value: {
2092
+ event: __spreadProps(__spreadValues({}, event), {
2093
+ mutationType: { type: "referenceChange" }
2094
+ }),
2095
+ form
2096
+ }
1578
2097
  });
1579
- return change(name, value);
1580
- };
1581
- const _a = form.finalForm.mutators, { insert, move, remove } = _a, rest = __objRest(_a, ["insert", "move", "remove"]);
1582
- const prepareNewUpdate = (name, lookup) => {
1583
- const extra = {};
1584
- if (lookup) {
1585
- extra["lookup"] = lookup;
1586
- }
1587
- const referenceName = name.split(".").filter((item) => isNaN(Number(item))).join(".");
1588
- setNewUpdate(__spreadValues({
1589
- queryName,
1590
- get: [queryName, "values", name].join("."),
1591
- set: [queryName, "data", name].join("."),
1592
- setReference: [queryName, "data", referenceName].join(".")
1593
- }, extra));
1594
- };
1595
- form.finalForm.mutators = __spreadValues({
1596
- insert: (...args) => {
1597
- const fieldName = args[0];
1598
- prepareNewUpdate(fieldName, fieldName);
1599
- insert(...args);
1600
- },
1601
- move: (...args) => {
1602
- const fieldName = args[0];
1603
- prepareNewUpdate(fieldName, fieldName);
1604
- move(...args);
1605
- },
1606
- remove: (...args) => {
1607
- const fieldName = args[0];
1608
- prepareNewUpdate(fieldName, fieldName);
1609
- remove(...args);
1610
- }
1611
- }, rest);
1612
- form.subscribe(({ values }) => {
1613
- setFormValues(__spreadProps(__spreadValues({}, formValues), { [queryName]: { values } }));
1614
- }, { values: true });
2098
+ } else {
2099
+ dispatch({ type: "onFieldChange", value: { event } });
2100
+ }
1615
2101
  });
1616
- }).catch((e) => {
1617
- cms.alerts.error("There was a problem setting up forms for your query");
1618
- console.error("There was a problem setting up forms for your query");
1619
- console.error(e);
1620
- setIsLoading(false);
2102
+ dispatch({ type: "done" });
2103
+ }
2104
+ }, [state.status]);
2105
+ React__default["default"].useEffect(() => {
2106
+ state.changeSets.forEach((changeSet) => {
2107
+ if (changeSet.mutationType.type === "reset") {
2108
+ const form = cms.forms.find(changeSet.formId);
2109
+ resolveSubFields({
2110
+ formNode: changeSet.formNode,
2111
+ form,
2112
+ loc: []
2113
+ }).then((res) => {
2114
+ dispatch({
2115
+ type: "setIn",
2116
+ value: {
2117
+ value: res,
2118
+ path: changeSet.path
2119
+ }
2120
+ });
2121
+ });
2122
+ return;
2123
+ } else if (changeSet.mutationType.type === "insert") {
2124
+ if (changeSet.fieldDefinition.type === "object") {
2125
+ const fieldName = changeSet.fieldDefinition.list ? `${changeSet.name}.[]` : changeSet.name;
2126
+ const { fields, __typename } = getSubFields(changeSet);
2127
+ resolveSubFields({
2128
+ formNode: changeSet.formNode,
2129
+ prefix: replaceRealNum(fieldName),
2130
+ loc: [...stripIndices(changeSet.path), 0],
2131
+ form: {
2132
+ fields,
2133
+ values: changeSet.value[0]
2134
+ }
2135
+ }).then((res) => {
2136
+ const extra = {};
2137
+ if (__typename) {
2138
+ extra["__typename"] = __typename;
2139
+ }
2140
+ dispatch({
2141
+ type: "setIn",
2142
+ value: __spreadProps(__spreadValues({
2143
+ displaceIndex: true
2144
+ }, changeSet), {
2145
+ value: __spreadValues(__spreadValues({}, res), extra)
2146
+ })
2147
+ });
2148
+ });
2149
+ } else {
2150
+ dispatch({
2151
+ type: "setIn",
2152
+ value: __spreadProps(__spreadValues({
2153
+ displaceIndex: true
2154
+ }, changeSet), {
2155
+ value: changeSet.value[0]
2156
+ })
2157
+ });
2158
+ }
2159
+ } else {
2160
+ if (changeSet.mutationType.type === "referenceChange") {
2161
+ const { formNode } = changeSet;
2162
+ const blueprint = getFormNodeBlueprint(formNode, state);
2163
+ if (!changeSet.value) {
2164
+ dispatch({
2165
+ type: "setIn",
2166
+ value: __spreadProps(__spreadValues({}, changeSet), {
2167
+ value: null
2168
+ })
2169
+ });
2170
+ } else {
2171
+ cms.api.tina.request(`
2172
+ query Node($id: String!) {
2173
+ node(id: $id) {
2174
+ ${G__namespace.print(blueprint.selection)}
2175
+ }
2176
+ }
2177
+ `, { variables: { id: changeSet.value } }).then(async (res) => {
2178
+ const form = state.documentForms.find((documentForm) => documentForm.id === formNode.documentFormId);
2179
+ const data = await resolveSubFields({
2180
+ formNode,
2181
+ form,
2182
+ loc: formNode.location
2183
+ });
2184
+ dispatch({
2185
+ type: "setIn",
2186
+ value: __spreadProps(__spreadValues({}, changeSet), {
2187
+ value: __spreadProps(__spreadValues({}, res.node), {
2188
+ data
2189
+ })
2190
+ })
2191
+ });
2192
+ }).catch((e) => {
2193
+ cms.alerts.error(`Unexpected error fetching reference`);
2194
+ console.log(e);
2195
+ });
2196
+ }
2197
+ } else {
2198
+ dispatch({ type: "setIn", value: changeSet });
2199
+ }
2200
+ }
1621
2201
  });
2202
+ }, [state.changeSets.length]);
2203
+ React__default["default"].useEffect(() => {
2204
+ formIds.current = state.documentForms.map((df) => df.id);
2205
+ }, [state.documentForms.length]);
2206
+ React__default["default"].useEffect(() => {
1622
2207
  return () => {
1623
- formIds.forEach((name) => {
1624
- const formPlugin = cms.forms.find(name);
1625
- if (formPlugin) {
1626
- cms.forms.remove(formPlugin);
2208
+ formIds.current.forEach((formId) => {
2209
+ const form = cms.forms.find(formId);
2210
+ if (form) {
2211
+ cms.plugins.remove(form);
1627
2212
  }
1628
2213
  });
1629
2214
  };
1630
- }, [query, JSON.stringify(variables), currentBranch]);
1631
- return [data, isLoading];
1632
- }
1633
- const transformDocumentIntoMutationRequestPayload = (document, instructions) => {
1634
- const _a = document, { _collection, __typename, _template } = _a, rest = __objRest(_a, ["_collection", "__typename", "_template"]);
1635
- const params = transformParams(rest);
1636
- const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
1637
- return instructions.includeCollection ? { [_collection]: paramsWithTemplate } : paramsWithTemplate;
1638
- };
1639
- const transformParams = (data) => {
1640
- if (["string", "number", "boolean"].includes(typeof data)) {
2215
+ }, []);
2216
+ const resolveSubFields = React__default["default"].useCallback(async (args) => {
2217
+ const { form, formNode, prefix, loc } = args;
2218
+ const data = {};
2219
+ await sequential(form.fields, async (field) => {
2220
+ const value = form.values[field.name];
2221
+ const blueprint = getFormNodeBlueprint(formNode, state);
2222
+ const { matchName, fieldName } = getMatchName({
2223
+ field,
2224
+ prefix,
2225
+ blueprint
2226
+ });
2227
+ const fieldBlueprints = blueprint.fields.filter((fieldBlueprint) => {
2228
+ return matchName === getBlueprintNamePath(fieldBlueprint);
2229
+ }).filter((fbp) => filterFieldBlueprintsByParentTypename(fbp, field.parentTypename));
2230
+ switch (field.type) {
2231
+ case "object":
2232
+ if (field.templates) {
2233
+ if (field.list) {
2234
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2235
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2236
+ if (!value) {
2237
+ data[keyName] = null;
2238
+ return true;
2239
+ }
2240
+ if (!Array.isArray(value)) {
2241
+ throw new Error(`Expected value for object list field to be an array`);
2242
+ }
2243
+ data[keyName] = await sequential(value, async (item, index) => {
2244
+ const template = field.templates[item._template];
2245
+ return __spreadProps(__spreadValues({}, await resolveSubFields({
2246
+ formNode,
2247
+ form: { fields: template.fields, values: item },
2248
+ prefix: prefix ? [prefix, fieldName].join(".") : fieldName,
2249
+ loc: [...loc, index]
2250
+ })), {
2251
+ __typename: field.typeMap[item._template]
2252
+ });
2253
+ });
2254
+ });
2255
+ } else {
2256
+ throw new Error("blocks without list true is not yet supported");
2257
+ }
2258
+ } else {
2259
+ if (field.list) {
2260
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2261
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2262
+ if (!value) {
2263
+ data[keyName] = null;
2264
+ return true;
2265
+ }
2266
+ if (!Array.isArray(value)) {
2267
+ throw new Error(`Expected value for object list field to be an array`);
2268
+ }
2269
+ data[keyName] = await sequential(value, async (item, index) => {
2270
+ return resolveSubFields({
2271
+ formNode,
2272
+ form: { fields: field.fields, values: item },
2273
+ prefix: [prefix, fieldName].join("."),
2274
+ loc: [...loc, index]
2275
+ });
2276
+ });
2277
+ return true;
2278
+ });
2279
+ } else {
2280
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2281
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2282
+ if (!value) {
2283
+ data[keyName] = null;
2284
+ return true;
2285
+ }
2286
+ data[keyName] = await resolveSubFields({
2287
+ formNode,
2288
+ form: { fields: field.fields, values: value },
2289
+ prefix: [prefix, fieldName].join("."),
2290
+ loc
2291
+ });
2292
+ return true;
2293
+ });
2294
+ }
2295
+ }
2296
+ break;
2297
+ case "reference":
2298
+ let form2;
2299
+ if (typeof value === "string") {
2300
+ const existingForm = cms.forms.find(value);
2301
+ if (existingForm) {
2302
+ form2 = existingForm;
2303
+ } else {
2304
+ const formInfo = await cms.api.tina.request(`#graphql
2305
+ query Node($id: String!) {
2306
+ node(id: $id) {
2307
+ ...on Document {
2308
+ form
2309
+ values
2310
+ _internalSys: sys {
2311
+ path
2312
+ collection {
2313
+ name
2314
+ }
2315
+ }
2316
+ }
2317
+ }
2318
+ }
2319
+ `, { variables: { id: value } });
2320
+ form2 = buildForm(formInfo.node, cms, formifyFunc, false, onSubmit);
2321
+ }
2322
+ }
2323
+ await sequential(fieldBlueprints, async (fieldBlueprint) => {
2324
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2325
+ if (!value) {
2326
+ data[keyName] = null;
2327
+ return true;
2328
+ }
2329
+ const documentBlueprint = state.blueprints.find((dp) => getBlueprintNamePath(dp) === matchName);
2330
+ const location = [...formNode.location];
2331
+ if (loc) {
2332
+ loc.forEach((item) => location.push(item));
2333
+ }
2334
+ const subDocumentFormNode = buildFormNode(documentBlueprint, form2, location);
2335
+ dispatch({
2336
+ type: "addOrReplaceDocumentFormNode",
2337
+ value: {
2338
+ formNode: subDocumentFormNode,
2339
+ documentForm: form2
2340
+ }
2341
+ });
2342
+ const res = await cms.api.tina.request(`
2343
+ query Node($id: String!) {
2344
+ node(id: $id) {
2345
+ ${G__namespace.print(documentBlueprint.selection)}
2346
+ }
2347
+ }
2348
+ `, { variables: { id: value } });
2349
+ data[keyName] = __spreadProps(__spreadValues({}, res.node), {
2350
+ data: await resolveSubFields({
2351
+ formNode: subDocumentFormNode,
2352
+ form: form2,
2353
+ loc: location
2354
+ })
2355
+ });
2356
+ });
2357
+ break;
2358
+ default:
2359
+ fieldBlueprints.forEach((fieldBlueprint) => {
2360
+ const keyName = getFieldNameOrAlias(fieldBlueprint);
2361
+ if (!value) {
2362
+ data[keyName] = null;
2363
+ } else {
2364
+ data[keyName] = value;
2365
+ }
2366
+ });
2367
+ break;
2368
+ }
2369
+ return true;
2370
+ });
1641
2371
  return data;
2372
+ }, [cms, JSON.stringify(state), dispatch]);
2373
+ return __spreadProps(__spreadValues({}, state), {
2374
+ queryString: G__namespace.print(state.query)
2375
+ });
2376
+ };
2377
+ const buildFormNode = (documentBlueprint, form, location) => {
2378
+ return {
2379
+ documentBlueprintId: documentBlueprint.id,
2380
+ documentFormId: form.id,
2381
+ location
2382
+ };
2383
+ };
2384
+ const captureBranchName = /^refs\/heads\/(.*)/;
2385
+ const parseRefForBranchName = (ref) => {
2386
+ const matches = ref.match(captureBranchName);
2387
+ return matches[1];
2388
+ };
2389
+ class Client {
2390
+ constructor(_a) {
2391
+ var _b = _a, { tokenStorage = "MEMORY" } = _b, options = __objRest(_b, ["tokenStorage"]);
2392
+ this.events = new toolkit.EventBus();
2393
+ this.addPendingContent = async (props) => {
2394
+ const mutation = `#graphql
2395
+ mutation addPendingDocumentMutation(
2396
+ $relativePath: String!
2397
+ $collection: String!
2398
+ $template: String
2399
+ ) {
2400
+ addPendingDocument(
2401
+ relativePath: $relativePath
2402
+ template: $template
2403
+ collection: $collection
2404
+ ) {
2405
+ ... on Document {
2406
+ sys {
2407
+ relativePath
2408
+ path
2409
+ breadcrumbs
2410
+ collection {
2411
+ slug
2412
+ }
2413
+ }
2414
+ }
2415
+ }
2416
+ }`;
2417
+ const result = await this.request(mutation, {
2418
+ variables: props
2419
+ });
2420
+ return result;
2421
+ };
2422
+ this.getSchema = async () => {
2423
+ if (!this.gqlSchema) {
2424
+ const data = await this.request(G.getIntrospectionQuery(), {
2425
+ variables: {}
2426
+ });
2427
+ this.gqlSchema = G.buildClientSchema(data);
2428
+ }
2429
+ return this.gqlSchema;
2430
+ };
2431
+ this.getOptimizedQuery = async (documentNode) => {
2432
+ const data = await this.request(`query GetOptimizedQuery($queryString: String!) {
2433
+ getOptimizedQuery(queryString: $queryString)
2434
+ }`, {
2435
+ variables: { queryString: G.print(documentNode) }
2436
+ });
2437
+ return G.parse(data.getOptimizedQuery);
2438
+ };
2439
+ if (options.schema) {
2440
+ const enrichedSchema = new schemaTools.TinaSchema(__spreadValues({
2441
+ version: { fullVersion: "", major: "", minor: "", patch: "" },
2442
+ meta: { flags: [] }
2443
+ }, schemaTools.addNamespaceToSchema(options.schema, [])));
2444
+ this.schema = enrichedSchema;
2445
+ }
2446
+ this.options = options;
2447
+ this.setBranch(options.branch);
2448
+ this.events.subscribe("branch:change", ({ branchName }) => {
2449
+ this.setBranch(branchName);
2450
+ });
2451
+ this.clientId = options.clientId;
2452
+ switch (tokenStorage) {
2453
+ case "LOCAL_STORAGE":
2454
+ this.getToken = async function() {
2455
+ const tokens = localStorage.getItem(AUTH_TOKEN_KEY) || null;
2456
+ if (tokens) {
2457
+ return await this.getRefreshedToken(tokens);
2458
+ } else {
2459
+ return {
2460
+ access_token: null,
2461
+ id_token: null,
2462
+ refresh_token: null
2463
+ };
2464
+ }
2465
+ };
2466
+ this.setToken = function(token) {
2467
+ localStorage.setItem(AUTH_TOKEN_KEY, JSON.stringify(token, null, 2));
2468
+ };
2469
+ break;
2470
+ case "MEMORY":
2471
+ this.getToken = async () => {
2472
+ if (this.token) {
2473
+ return await this.getRefreshedToken(this.token);
2474
+ } else {
2475
+ return {
2476
+ access_token: null,
2477
+ id_token: null,
2478
+ refresh_token: null
2479
+ };
2480
+ }
2481
+ };
2482
+ this.setToken = (token) => {
2483
+ this.token = JSON.stringify(token, null, 2);
2484
+ };
2485
+ break;
2486
+ case "CUSTOM":
2487
+ if (!options.getTokenFn) {
2488
+ throw new Error("When CUSTOM token storage is selected, a getTokenFn must be provided");
2489
+ }
2490
+ this.getToken = options.getTokenFn;
2491
+ break;
2492
+ }
2493
+ }
2494
+ get isLocalMode() {
2495
+ return this.contentApiUrl.includes("localhost");
2496
+ }
2497
+ setBranch(branchName) {
2498
+ var _a, _b, _c;
2499
+ const encodedBranch = encodeURIComponent(branchName);
2500
+ this.frontendUrl = ((_a = this.options.tinaioConfig) == null ? void 0 : _a.frontendUrlOverride) || "https://app.tina.io";
2501
+ this.identityApiUrl = ((_b = this.options.tinaioConfig) == null ? void 0 : _b.identityApiUrlOverride) || "https://identity.tinajs.io";
2502
+ this.contentApiBase = ((_c = this.options.tinaioConfig) == null ? void 0 : _c.contentApiUrlOverride) || `https://content.tinajs.io`;
2503
+ this.contentApiUrl = this.options.customContentApiUrl || `${this.contentApiBase}/content/${this.options.clientId}/github/${encodedBranch}`;
2504
+ }
2505
+ async requestWithForm(query, {
2506
+ variables,
2507
+ useUnstableFormify
2508
+ }) {
2509
+ const schema = await this.getSchema();
2510
+ let formifiedQuery;
2511
+ if (useUnstableFormify) {
2512
+ const res = await formify({
2513
+ schema,
2514
+ query: G.print(query(gql__default["default"])),
2515
+ getOptimizedQuery: this.getOptimizedQuery
2516
+ });
2517
+ formifiedQuery = res.formifiedQuery;
2518
+ } else {
2519
+ formifiedQuery = formify$1(query(gql__default["default"]), schema);
2520
+ }
2521
+ return this.request(G.print(formifiedQuery), { variables });
2522
+ }
2523
+ async request(query, { variables }) {
2524
+ const res = await fetch(this.contentApiUrl, {
2525
+ method: "POST",
2526
+ headers: {
2527
+ "Content-Type": "application/json",
2528
+ Authorization: "Bearer " + (await this.getToken()).id_token
2529
+ },
2530
+ body: JSON.stringify({
2531
+ query: typeof query === "function" ? G.print(query(gql__default["default"])) : query,
2532
+ variables
2533
+ })
2534
+ });
2535
+ if (res.status !== 200) {
2536
+ throw new Error(`Unable to complete request, ${res.statusText}`);
2537
+ }
2538
+ const json = await res.json();
2539
+ if (json.errors) {
2540
+ throw new Error(`Unable to fetch, errors:
2541
+ ${json.errors.map((error) => error.message).join("\n")}`);
2542
+ }
2543
+ return json.data;
2544
+ }
2545
+ parseJwt(token) {
2546
+ const base64Url = token.split(".")[1];
2547
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
2548
+ const jsonPayload = decodeURIComponent(atob(base64).split("").map(function(c) {
2549
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
2550
+ }).join(""));
2551
+ return JSON.parse(jsonPayload);
2552
+ }
2553
+ async getRefreshedToken(tokens) {
2554
+ const { access_token, id_token, refresh_token } = JSON.parse(tokens);
2555
+ const { exp, iss, client_id } = this.parseJwt(access_token);
2556
+ if (Date.now() / 1e3 >= exp - 120) {
2557
+ const refreshResponse = await fetch(iss, {
2558
+ method: "POST",
2559
+ headers: {
2560
+ "Content-Type": "application/x-amz-json-1.1",
2561
+ "x-amz-target": "AWSCognitoIdentityProviderService.InitiateAuth"
2562
+ },
2563
+ body: JSON.stringify({
2564
+ ClientId: client_id,
2565
+ AuthFlow: "REFRESH_TOKEN_AUTH",
2566
+ AuthParameters: {
2567
+ REFRESH_TOKEN: refresh_token,
2568
+ DEVICE_KEY: null
2569
+ }
2570
+ })
2571
+ });
2572
+ if (refreshResponse.status !== 200) {
2573
+ throw new Error("Unable to refresh auth tokens");
2574
+ }
2575
+ const responseJson = await refreshResponse.json();
2576
+ const newToken = {
2577
+ access_token: responseJson.AuthenticationResult.AccessToken,
2578
+ id_token: responseJson.AuthenticationResult.IdToken,
2579
+ refresh_token
2580
+ };
2581
+ this.setToken(newToken);
2582
+ return Promise.resolve(newToken);
2583
+ }
2584
+ return Promise.resolve({ access_token, id_token, refresh_token });
2585
+ }
2586
+ async isAuthorized() {
2587
+ return this.isAuthenticated();
2588
+ }
2589
+ async isAuthenticated() {
2590
+ return !!await this.getUser();
2591
+ }
2592
+ async authenticate() {
2593
+ const token = await authenticate(this.clientId, this.frontendUrl);
2594
+ this.setToken(token);
2595
+ return token;
2596
+ }
2597
+ async fetchWithToken(input, init) {
2598
+ const headers = (init == null ? void 0 : init.headers) || {};
2599
+ return await fetch(input, __spreadProps(__spreadValues({}, init), {
2600
+ headers: new Headers(__spreadValues({
2601
+ Authorization: "Bearer " + (await this.getToken()).id_token
2602
+ }, headers))
2603
+ }));
2604
+ }
2605
+ async getUser() {
2606
+ if (!this.clientId) {
2607
+ return null;
2608
+ }
2609
+ const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
2610
+ try {
2611
+ const res = await this.fetchWithToken(url, {
2612
+ method: "GET"
2613
+ });
2614
+ const val = await res.json();
2615
+ if (!res.status.toString().startsWith("2")) {
2616
+ console.error(val.error);
2617
+ return null;
2618
+ }
2619
+ return val;
2620
+ } catch (e) {
2621
+ console.error(e);
2622
+ return null;
2623
+ }
2624
+ }
2625
+ async listBranches() {
2626
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2627
+ const res = await this.fetchWithToken(url, {
2628
+ method: "GET"
2629
+ });
2630
+ return res.json();
2631
+ }
2632
+ async createBranch({ baseBranch, branchName }) {
2633
+ const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
2634
+ try {
2635
+ const res = await this.fetchWithToken(url, {
2636
+ method: "POST",
2637
+ body: JSON.stringify({
2638
+ baseBranch,
2639
+ branchName
2640
+ }),
2641
+ headers: {
2642
+ "Content-Type": "application/json"
2643
+ }
2644
+ });
2645
+ return await res.json().then((r) => parseRefForBranchName(r.data.ref));
2646
+ } catch (error) {
2647
+ console.error("There was an error creating a new branch.", error);
2648
+ return null;
2649
+ }
2650
+ }
2651
+ }
2652
+ const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
2653
+ class LocalClient extends Client {
2654
+ constructor(props) {
2655
+ const clientProps = __spreadProps(__spreadValues({}, props), {
2656
+ clientId: "",
2657
+ branch: "",
2658
+ customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
2659
+ });
2660
+ super(clientProps);
2661
+ }
2662
+ async isAuthorized() {
2663
+ return true;
2664
+ }
2665
+ async isAuthenticated() {
2666
+ return true;
2667
+ }
2668
+ }
2669
+ function ModalBuilder(modalProps) {
2670
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalPopup, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, null, modalProps.title), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalBody, {
2671
+ padded: true
2672
+ }, /* @__PURE__ */ React__default["default"].createElement("p", null, modalProps.message), modalProps.error && /* @__PURE__ */ React__default["default"].createElement(ErrorLabel, null, modalProps.error)), /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalActions, null, modalProps.actions.map((action) => /* @__PURE__ */ React__default["default"].createElement(AsyncButton, __spreadValues({
2673
+ key: action.name
2674
+ }, action))))));
2675
+ }
2676
+ const ErrorLabel = styled__default["default"].p`
2677
+ color: var(--tina-color-error) !important;
2678
+ `;
2679
+ const AsyncButton = ({ name, primary, action }) => {
2680
+ const [submitting, setSubmitting] = React.useState(false);
2681
+ const onClick = React.useCallback(async () => {
2682
+ setSubmitting(true);
2683
+ try {
2684
+ await action();
2685
+ setSubmitting(false);
2686
+ } catch (e) {
2687
+ setSubmitting(false);
2688
+ throw e;
2689
+ }
2690
+ }, [action, setSubmitting]);
2691
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
2692
+ variant: primary ? "primary" : "secondary",
2693
+ onClick,
2694
+ busy: submitting,
2695
+ disabled: submitting
2696
+ }, submitting && /* @__PURE__ */ React__default["default"].createElement(toolkit.LoadingDots, null), !submitting && name);
2697
+ };
2698
+ const TINA_AUTH_CONFIG = "tina_auth_config";
2699
+ const useTinaAuthRedirect = () => {
2700
+ React.useEffect(() => {
2701
+ const urlParams = new URLSearchParams(window.location.search);
2702
+ const config = {
2703
+ code: urlParams.get("code") || "",
2704
+ scope: urlParams.get("scope") || "email",
2705
+ state: urlParams.get("state")
2706
+ };
2707
+ if (!config.code) {
2708
+ return;
2709
+ }
2710
+ localStorage[TINA_AUTH_CONFIG] = JSON.stringify(config);
2711
+ }, []);
2712
+ };
2713
+ class TinaAdminApi {
2714
+ constructor(cms) {
2715
+ this.api = cms.api.tina;
2716
+ }
2717
+ async isAuthenticated() {
2718
+ return await this.api.isAuthenticated();
2719
+ }
2720
+ async fetchCollections() {
2721
+ const response = await this.api.request(`#graphql
2722
+ query{
2723
+ getCollections {
2724
+ label,
2725
+ name
2726
+ }
2727
+ }`, { variables: {} });
2728
+ return response;
2729
+ }
2730
+ async fetchCollection(collectionName, includeDocuments) {
2731
+ const response = await this.api.request(`#graphql
2732
+ query($collection: String!, $includeDocuments: Boolean!){
2733
+ getCollection(collection: $collection){
2734
+ name
2735
+ label
2736
+ format
2737
+ templates
2738
+ documents @include(if: $includeDocuments) {
2739
+ totalCount
2740
+ edges {
2741
+ node {
2742
+ ... on Document {
2743
+ sys {
2744
+ template
2745
+ breadcrumbs
2746
+ path
2747
+ basename
2748
+ relativePath
2749
+ filename
2750
+ extension
2751
+ }
2752
+ }
2753
+ }
2754
+ }
2755
+ }
2756
+ }
2757
+ }`, { variables: { collection: collectionName, includeDocuments } });
2758
+ return response;
2759
+ }
2760
+ async fetchDocument(collectionName, relativePath) {
2761
+ const response = await this.api.request(`#graphql
2762
+ query($collection: String!, $relativePath: String!) {
2763
+ getDocument(collection:$collection, relativePath:$relativePath) {
2764
+ ... on Document {
2765
+ form
2766
+ values
2767
+ }
2768
+ }
2769
+ }`, { variables: { collection: collectionName, relativePath } });
2770
+ return response;
1642
2771
  }
1643
- if (Array.isArray(data)) {
1644
- return data.map((item) => transformParams(item));
2772
+ async fetchDocumentFields() {
2773
+ const response = await this.api.request(`#graphql
2774
+ query {
2775
+ getDocumentFields
2776
+ }`, { variables: {} });
2777
+ return response;
1645
2778
  }
1646
- try {
1647
- assertShape(data, (yup2) => yup2.object({ _template: yup2.string().required() }));
1648
- const _a = data, { _template, __typename } = _a, rest = __objRest(_a, ["_template", "__typename"]);
1649
- const nested = transformParams(rest);
1650
- return { [_template]: nested };
1651
- } catch (e) {
1652
- if (e.message === "Failed to assertShape - _template is a required field") {
1653
- if (!data) {
1654
- return [];
2779
+ async createDocument(collectionName, relativePath, params) {
2780
+ const response = await this.api.request(`#graphql
2781
+ mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
2782
+ createDocument(
2783
+ collection: $collection,
2784
+ relativePath: $relativePath,
2785
+ params: $params
2786
+ ){__typename}
2787
+ }`, {
2788
+ variables: {
2789
+ collection: collectionName,
2790
+ relativePath,
2791
+ params
1655
2792
  }
1656
- const accum = {};
1657
- Object.entries(data).map(([keyName, value]) => {
1658
- accum[keyName] = transformParams(value);
1659
- });
1660
- return accum;
1661
- } else {
1662
- if (!data) {
1663
- return [];
2793
+ });
2794
+ return response;
2795
+ }
2796
+ async updateDocument(collectionName, relativePath, params) {
2797
+ const response = await this.api.request(`#graphql
2798
+ mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
2799
+ updateDocument(
2800
+ collection: $collection,
2801
+ relativePath: $relativePath,
2802
+ params: $params
2803
+ ){__typename}
2804
+ }`, {
2805
+ variables: {
2806
+ collection: collectionName,
2807
+ relativePath,
2808
+ params
1664
2809
  }
1665
- throw e;
1666
- }
2810
+ });
2811
+ return response;
1667
2812
  }
1668
- };
1669
- const getFieldUpdate = (newUpdate, activeForm, formValues) => {
1670
- const items = newUpdate.lookup.split(".");
1671
- let currentFields = activeForm.fields;
1672
- items.map((item, index) => {
1673
- const lookupName = items.slice(0, index + 1).join(".");
1674
- const value = finalForm.getIn(formValues, [newUpdate.queryName, "values", lookupName].join("."));
1675
- if (isNaN(Number(item))) {
1676
- if (Array.isArray(currentFields)) {
1677
- currentFields = currentFields.find((field) => field.name === item);
2813
+ }
2814
+ function sleep(ms) {
2815
+ return new Promise((resolve) => setTimeout(resolve, ms));
2816
+ }
2817
+ const AuthWallInner = ({
2818
+ children,
2819
+ cms,
2820
+ loginScreen,
2821
+ getModalActions
2822
+ }) => {
2823
+ const client = cms.api.tina;
2824
+ const [activeModal, setActiveModal] = React.useState(null);
2825
+ const [showChildren, setShowChildren] = React.useState(false);
2826
+ React__default["default"].useEffect(() => {
2827
+ client.isAuthenticated().then((isAuthenticated) => {
2828
+ if (isAuthenticated) {
2829
+ setShowChildren(true);
2830
+ cms.enable();
2831
+ } else {
2832
+ sleep(500).then(() => {
2833
+ setActiveModal("authenticate");
2834
+ });
1678
2835
  }
2836
+ });
2837
+ }, []);
2838
+ const onAuthSuccess = async () => {
2839
+ if (await client.isAuthenticated()) {
2840
+ setShowChildren(true);
2841
+ setActiveModal(null);
1679
2842
  } else {
1680
- const template = currentFields.templates ? currentFields.templates[value._template] : currentFields;
1681
- currentFields = template.fields;
2843
+ throw new Error("No access to repo");
1682
2844
  }
1683
- });
1684
- return currentFields;
2845
+ };
2846
+ const otherModalActions = getModalActions ? getModalActions({
2847
+ closeModal: () => {
2848
+ setActiveModal(null);
2849
+ }
2850
+ }) : [];
2851
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, activeModal === "authenticate" && /* @__PURE__ */ React__default["default"].createElement(ModalBuilder, {
2852
+ title: "Tina Cloud Authorization",
2853
+ message: "To save edits, Tina Cloud authorization is required. On save, changes will get commited using your account.",
2854
+ close,
2855
+ actions: [
2856
+ ...otherModalActions,
2857
+ {
2858
+ action: async () => {
2859
+ sharedctx.setEditing(false);
2860
+ window.location.reload();
2861
+ },
2862
+ name: "Close",
2863
+ primary: false
2864
+ },
2865
+ {
2866
+ name: "Continue to Tina Cloud",
2867
+ action: async () => {
2868
+ await client.authenticate();
2869
+ onAuthSuccess();
2870
+ },
2871
+ primary: true
2872
+ }
2873
+ ]
2874
+ }), showChildren ? children : loginScreen ? loginScreen : null);
1685
2875
  };
1686
- const generateFormCreators = (cms) => {
1687
- const createForm = (formConfig) => {
1688
- const form = new toolkit.Form(formConfig);
1689
- cms.forms.add(form);
1690
- return form;
2876
+ const TinaCloudProvider = (props) => {
2877
+ const baseBranch = props.branch || "main";
2878
+ const [currentBranch, setCurrentBranch] = toolkit.useLocalStorage("tinacms-current-branch", baseBranch);
2879
+ useTinaAuthRedirect();
2880
+ const cms = React__default["default"].useMemo(() => props.cms || new toolkit.TinaCMS({
2881
+ enabled: true,
2882
+ sidebar: true
2883
+ }), [props.cms]);
2884
+ if (!cms.api.tina) {
2885
+ cms.registerApi("tina", createClient(props));
2886
+ }
2887
+ if (!cms.api.admin) {
2888
+ cms.registerApi("admin", new TinaAdminApi(cms));
2889
+ }
2890
+ const setupMedia = async () => {
2891
+ var _a;
2892
+ if (props.mediaStore) {
2893
+ if ((_a = props.mediaStore.prototype) == null ? void 0 : _a.persist) {
2894
+ cms.media.store = new props.mediaStore(cms.api.tina);
2895
+ } else {
2896
+ const MediaClass = await props.mediaStore();
2897
+ cms.media.store = new MediaClass(cms.api.tina);
2898
+ }
2899
+ }
1691
2900
  };
1692
- const createGlobalForm = (formConfig, options) => {
1693
- const form = new toolkit.Form(formConfig);
1694
- cms.plugins.add(new toolkit.GlobalFormPlugin(form, options == null ? void 0 : options.icon, options == null ? void 0 : options.layout));
1695
- return form;
2901
+ const handleListBranches = async () => {
2902
+ const { owner, repo } = props;
2903
+ const branches = await cms.api.tina.listBranches({ owner, repo });
2904
+ if (!Array.isArray(branches)) {
2905
+ return [];
2906
+ }
2907
+ return branches;
1696
2908
  };
1697
- return { createForm, createGlobalForm };
2909
+ const handleCreateBranch = async (data) => {
2910
+ const newBranch = await cms.api.tina.createBranch(data);
2911
+ return newBranch;
2912
+ };
2913
+ setupMedia();
2914
+ const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
2915
+ React__default["default"].useEffect(() => {
2916
+ cms.events.subscribe("flag:set", ({ key, value }) => {
2917
+ if (key === "branch-switcher") {
2918
+ setBranchingEnabled(value);
2919
+ }
2920
+ });
2921
+ }, [cms.events]);
2922
+ React__default["default"].useEffect(() => {
2923
+ let branchSwitcher;
2924
+ if (branchingEnabled) {
2925
+ branchSwitcher = new toolkit.BranchSwitcherPlugin({
2926
+ listBranches: handleListBranches,
2927
+ createBranch: handleCreateBranch
2928
+ });
2929
+ cms.plugins.add(branchSwitcher);
2930
+ }
2931
+ return () => {
2932
+ if (branchingEnabled && branchSwitcher) {
2933
+ cms.plugins.remove(branchSwitcher);
2934
+ }
2935
+ };
2936
+ }, [branchingEnabled, props.branch]);
2937
+ React__default["default"].useEffect(() => {
2938
+ if (props.cmsCallback) {
2939
+ props.cmsCallback(cms);
2940
+ }
2941
+ }, []);
2942
+ return /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchDataProvider, {
2943
+ currentBranch,
2944
+ setCurrentBranch: (b) => {
2945
+ setCurrentBranch(b);
2946
+ }
2947
+ }, /* @__PURE__ */ React__default["default"].createElement(toolkit.TinaProvider, {
2948
+ cms
2949
+ }, /* @__PURE__ */ React__default["default"].createElement(AuthWallInner, __spreadProps(__spreadValues({}, props), {
2950
+ cms
2951
+ }))));
1698
2952
  };
2953
+ const TinaCloudAuthWall = TinaCloudProvider;
1699
2954
  class ContentCreatorPlugin {
1700
2955
  constructor(options) {
1701
2956
  this.__type = "content-creator";
@@ -1976,11 +3231,13 @@ mutation addPendingDocumentMutation(
1976
3231
  var _d = _c, {
1977
3232
  query,
1978
3233
  documentCreatorCallback,
1979
- formifyCallback
3234
+ formifyCallback,
3235
+ schema
1980
3236
  } = _d, props = __objRest(_d, [
1981
3237
  "query",
1982
3238
  "documentCreatorCallback",
1983
- "formifyCallback"
3239
+ "formifyCallback",
3240
+ "schema"
1984
3241
  ]);
1985
3242
  const validOldSetup = new Boolean(props == null ? void 0 : props.isLocalClient) || new Boolean(props == null ? void 0 : props.clientId) && new Boolean(props == null ? void 0 : props.branch);
1986
3243
  if (!props.apiURL && !validOldSetup) {
@@ -1997,7 +3254,8 @@ mutation addPendingDocumentMutation(
1997
3254
  tinaioConfig: props.tinaioConfig,
1998
3255
  isLocalClient,
1999
3256
  cmsCallback: props.cmsCallback,
2000
- mediaStore: props.mediaStore
3257
+ mediaStore: props.mediaStore,
3258
+ schema
2001
3259
  }, /* @__PURE__ */ React__default["default"].createElement("style", null, styles), /* @__PURE__ */ React__default["default"].createElement(ErrorBoundary, null, /* @__PURE__ */ React__default["default"].createElement(DocumentCreator, {
2002
3260
  documentCreatorCallback
2003
3261
  }), /* @__PURE__ */ React__default["default"].createElement(TinaDataProvider, {
@@ -2039,13 +3297,25 @@ mutation addPendingDocumentMutation(
2039
3297
  payload: void 0,
2040
3298
  isLoading: true
2041
3299
  });
3300
+ const cms = toolkit.useCMS();
3301
+ const useUnstableFormify = React__default["default"].useMemo(() => {
3302
+ if ((cms == null ? void 0 : cms.flags.get("use-unstable-formify")) === false) {
3303
+ return false;
3304
+ }
3305
+ return true;
3306
+ }, [cms == null ? void 0 : cms.flags]);
2042
3307
  return /* @__PURE__ */ React__default["default"].createElement(sharedctx.TinaDataContext.Provider, {
2043
3308
  value: {
2044
3309
  setRequest,
2045
3310
  isLoading: state.isLoading,
2046
3311
  state: { payload: state.payload }
2047
3312
  }
2048
- }, /* @__PURE__ */ React__default["default"].createElement(FormRegistrar, {
3313
+ }, useUnstableFormify ? /* @__PURE__ */ React__default["default"].createElement(FormRegistrarUnstable, {
3314
+ key: request == null ? void 0 : request.query,
3315
+ request,
3316
+ formifyCallback,
3317
+ onPayloadStateChange: setState
3318
+ }) : /* @__PURE__ */ React__default["default"].createElement(FormRegistrar, {
2049
3319
  key: request == null ? void 0 : request.query,
2050
3320
  request,
2051
3321
  formifyCallback,
@@ -2074,6 +3344,35 @@ mutation addPendingDocumentMutation(
2074
3344
  }, [JSON.stringify(payload), isLoading]);
2075
3345
  return isLoading ? /* @__PURE__ */ React__default["default"].createElement(Loader, null, /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null)) : null;
2076
3346
  };
3347
+ const FormRegistrarUnstable = (props) => {
3348
+ var _a;
3349
+ if (!((_a = props.request) == null ? void 0 : _a.query)) {
3350
+ return null;
3351
+ }
3352
+ return /* @__PURE__ */ React__default["default"].createElement(FormRegistrarUnstableInner, __spreadValues({}, props));
3353
+ };
3354
+ const FormRegistrarUnstableInner = ({
3355
+ request,
3356
+ formifyCallback,
3357
+ onPayloadStateChange
3358
+ }) => {
3359
+ const cms = toolkit.useCMS();
3360
+ const [payload, isLoading] = useGraphqlFormsUnstable({
3361
+ query: request == null ? void 0 : request.query,
3362
+ variables: request == null ? void 0 : request.variables,
3363
+ formify: (args) => {
3364
+ if (formifyCallback) {
3365
+ return formifyCallback(args, cms);
3366
+ } else {
3367
+ return args.createForm(args.formConfig);
3368
+ }
3369
+ }
3370
+ });
3371
+ React__default["default"].useEffect(() => {
3372
+ onPayloadStateChange({ payload, isLoading });
3373
+ }, [JSON.stringify(payload), isLoading]);
3374
+ return isLoading ? /* @__PURE__ */ React__default["default"].createElement(Loader, null, /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null)) : null;
3375
+ };
2077
3376
  const Loader = (props) => {
2078
3377
  return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
2079
3378
  style: {
@@ -2684,7 +3983,7 @@ This will work when developing locally but NOT when deployed to production.
2684
3983
  window.location.href = routeOverride;
2685
3984
  return null;
2686
3985
  } else {
2687
- navigate(document.sys.filename);
3986
+ navigate(document.sys.breadcrumbs.join("/"));
2688
3987
  }
2689
3988
  };
2690
3989
  const CollectionListPage = () => {
@@ -2717,8 +4016,9 @@ This will work when developing locally but NOT when deployed to production.
2717
4016
  }, /* @__PURE__ */ React__default["default"].createElement("tbody", {
2718
4017
  className: "divide-y divide-gray-150"
2719
4018
  }, documents.map((document) => {
4019
+ const subfolders = document.node.sys.breadcrumbs.slice(0, -1).join("/");
2720
4020
  return /* @__PURE__ */ React__default["default"].createElement("tr", {
2721
- key: `document-${document.node.sys.filename}`,
4021
+ key: `document-${document.node.sys.relativePath}`,
2722
4022
  className: ""
2723
4023
  }, /* @__PURE__ */ React__default["default"].createElement("td", {
2724
4024
  className: "px-6 py-2 whitespace-nowrap"
@@ -2733,7 +4033,9 @@ This will work when developing locally but NOT when deployed to production.
2733
4033
  className: "block text-xs text-gray-400 mb-1 uppercase"
2734
4034
  }, "Filename"), /* @__PURE__ */ React__default["default"].createElement("span", {
2735
4035
  className: "h-5 leading-5 block whitespace-nowrap"
2736
- }, document.node.sys.filename)))), /* @__PURE__ */ React__default["default"].createElement("td", {
4036
+ }, subfolders && /* @__PURE__ */ React__default["default"].createElement("span", {
4037
+ className: "text-xs text-gray-400"
4038
+ }, `${subfolders}/`), /* @__PURE__ */ React__default["default"].createElement("span", null, document.node.sys.filename))))), /* @__PURE__ */ React__default["default"].createElement("td", {
2737
4039
  className: "px-6 py-4 whitespace-nowrap"
2738
4040
  }, /* @__PURE__ */ React__default["default"].createElement("span", {
2739
4041
  className: "block text-xs text-gray-400 mb-1 uppercase"
@@ -2857,6 +4159,22 @@ This will work when developing locally but NOT when deployed to production.
2857
4159
  var _a, _b;
2858
4160
  const navigate = reactRouterDom.useNavigate();
2859
4161
  const [formIsPristine, setFormIsPristine] = React.useState(true);
4162
+ const schema = cms.api.tina.schema;
4163
+ let schemaFields = fields;
4164
+ if (schema) {
4165
+ const schemaCollection = schema.getCollection(collection.name);
4166
+ const template2 = schema.getTemplateForData({
4167
+ collection: schemaCollection,
4168
+ data: {}
4169
+ });
4170
+ const formInfo = schemaTools.resolveForm({
4171
+ collection: schemaCollection,
4172
+ basename: schemaCollection.name,
4173
+ schema,
4174
+ template: template2
4175
+ });
4176
+ schemaFields = formInfo.fields;
4177
+ }
2860
4178
  const form = React.useMemo(() => {
2861
4179
  return new toolkit.Form({
2862
4180
  id: "create-form",
@@ -2866,7 +4184,7 @@ This will work when developing locally but NOT when deployed to production.
2866
4184
  name: "filename",
2867
4185
  label: "Filename",
2868
4186
  component: "text",
2869
- description: `A unique filename for the content. Example: My_Document`,
4187
+ description: /* @__PURE__ */ React__default["default"].createElement("span", null, "A unique filename for the content.", /* @__PURE__ */ React__default["default"].createElement("br", null), "Examples: ", /* @__PURE__ */ React__default["default"].createElement("code", null, "My_Document"), ", ", /* @__PURE__ */ React__default["default"].createElement("code", null, "My_Document.en"), ",", " ", /* @__PURE__ */ React__default["default"].createElement("code", null, "sub-folder/My_Document")),
2870
4188
  placeholder: `My_Document`,
2871
4189
  validate: (value, allValues, meta) => {
2872
4190
  if (!value) {
@@ -2875,13 +4193,13 @@ This will work when developing locally but NOT when deployed to production.
2875
4193
  }
2876
4194
  return true;
2877
4195
  }
2878
- const isValid = /^[_a-zA-Z][-,_a-zA-Z0-9]*$/.test(value);
4196
+ const isValid = /^[_a-zA-Z][\.\-_\/a-zA-Z0-9]*$/.test(value);
2879
4197
  if (value && !isValid) {
2880
- return "Must begin with a-z, A-Z, or _ and contain only a-z, A-Z, 0-9, - or _";
4198
+ return "Must begin with a-z, A-Z, or _ and contain only a-z, A-Z, 0-9, -, _, ., or /.";
2881
4199
  }
2882
4200
  }
2883
4201
  },
2884
- ...fields
4202
+ ...schemaFields
2885
4203
  ],
2886
4204
  onSubmit: async (values) => {
2887
4205
  try {
@@ -2974,7 +4292,8 @@ This will work when developing locally but NOT when deployed to production.
2974
4292
  }
2975
4293
  };
2976
4294
  const CollectionUpdatePage = () => {
2977
- const { collectionName, filename } = reactRouterDom.useParams();
4295
+ const _a = reactRouterDom.useParams(), { collectionName } = _a, rest = __objRest(_a, ["collectionName"]);
4296
+ const { "*": filename } = rest;
2978
4297
  return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => /* @__PURE__ */ React__default["default"].createElement(GetDocumentFields, {
2979
4298
  cms,
2980
4299
  collectionName
@@ -3003,13 +4322,28 @@ This will work when developing locally but NOT when deployed to production.
3003
4322
  mutationInfo
3004
4323
  }) => {
3005
4324
  var _a, _b;
3006
- reactRouterDom.useNavigate();
3007
4325
  const [formIsPristine, setFormIsPristine] = React.useState(true);
4326
+ const schema = cms.api.tina.schema;
4327
+ let schemaFields = document.form.fields;
4328
+ if (schema) {
4329
+ const schemaCollection = schema.getCollection(collection.name);
4330
+ const template = schema.getTemplateForData({
4331
+ collection: schemaCollection,
4332
+ data: document.value
4333
+ });
4334
+ const formInfo = schemaTools.resolveForm({
4335
+ collection: schemaCollection,
4336
+ basename: schemaCollection.name,
4337
+ schema,
4338
+ template
4339
+ });
4340
+ schemaFields = formInfo.fields;
4341
+ }
3008
4342
  const form = React.useMemo(() => {
3009
4343
  return new toolkit.Form({
3010
4344
  id: "update-form",
3011
4345
  label: "form",
3012
- fields: document.form.fields,
4346
+ fields: schemaFields,
3013
4347
  initialValues: document.values,
3014
4348
  onSubmit: async (values) => {
3015
4349
  try {
@@ -3093,7 +4427,7 @@ This will work when developing locally but NOT when deployed to production.
3093
4427
  path: "collections/:collectionName/:templateName/new",
3094
4428
  element: /* @__PURE__ */ React__default["default"].createElement(CollectionCreatePage, null)
3095
4429
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
3096
- path: "collections/:collectionName/:filename",
4430
+ path: "collections/:collectionName/*",
3097
4431
  element: /* @__PURE__ */ React__default["default"].createElement(CollectionUpdatePage, null)
3098
4432
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
3099
4433
  path: "collections/:collectionName",
@@ -3151,6 +4485,7 @@ This will work when developing locally but NOT when deployed to production.
3151
4485
  exports2.staticRequest = staticRequest;
3152
4486
  exports2.useDocumentCreatorPlugin = useDocumentCreatorPlugin;
3153
4487
  exports2.useGraphqlForms = useGraphqlForms;
4488
+ exports2.useGraphqlFormsUnstable = useGraphqlFormsUnstable;
3154
4489
  exports2.useTinaAuthRedirect = useTinaAuthRedirect;
3155
4490
  Object.keys(toolkit).forEach(function(k) {
3156
4491
  if (k !== "default" && !exports2.hasOwnProperty(k))