tinacms 0.66.7 → 0.66.10

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