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