tinacms 0.66.8 → 0.67.0

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