tinacms 1.2.0 → 1.2.2

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.
@@ -1,6 +1,3 @@
1
- /**
2
-
3
- */
4
1
  import type { TinaCMS } from '@tinacms/toolkit';
5
2
  import type { TinaSchema } from '@tinacms/schema-tools';
6
3
  import type { Client } from '../internalClient';
@@ -18,6 +15,9 @@ export declare class TinaAdminApi {
18
15
  schema: TinaSchema;
19
16
  constructor(cms: TinaCMS);
20
17
  isAuthenticated(): Promise<boolean>;
18
+ checkGraphqlSchema({ localSchema }: {
19
+ localSchema: any;
20
+ }): Promise<boolean>;
21
21
  fetchCollections(): import("@tinacms/schema-tools").TinaCloudCollection<true>[];
22
22
  renameDocument({ collection, relativePath, newRelativePath }: {
23
23
  collection: any;
@@ -1,8 +1,6 @@
1
- /**
2
-
3
- */
4
1
  /// <reference types="react" />
5
- export declare const TinaAdmin: ({ preview, config, }: {
2
+ export declare const TinaAdmin: ({ preview, config, schemaJson, }: {
3
+ schemaJson?: any;
6
4
  preview?: (props: object) => JSX.Element;
7
5
  config: object;
8
6
  }) => JSX.Element;
package/dist/index.es.js CHANGED
@@ -1,16 +1,18 @@
1
- import { useCMS, Form, GlobalFormPlugin, EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, Nav, LocalWarning, BillingWarning, Select, Input, ReactDateTimeWithStyles, textFieldClasses, Toggle, OverflowMenu, CursorPaginator, PopupModal, BaseTextField, wrapFieldsWithMeta, FormStatus, FormBuilder } from "@tinacms/toolkit";
1
+ import { z } from "zod";
2
+ import { useCMS, Form, GlobalFormPlugin, EventBus, Modal, ModalPopup, ModalHeader, ModalBody, ModalActions, Button, LoadingDots, useLocalStorage, TinaCMS, BranchSwitcherPlugin, BranchDataProvider, TinaProvider, TinaMediaStore, DummyMediaStore, Nav, BranchBanner, LocalWarning, BillingWarning, Select, Input, ReactDateTimeWithStyles, textFieldClasses, Toggle, OverflowMenu, CursorPaginator, PopupModal, BaseTextField, wrapFieldsWithMeta, FormStatus, FormBuilder } from "@tinacms/toolkit";
2
3
  export * from "@tinacms/toolkit";
3
4
  export { MdxFieldPluginExtendible } from "@tinacms/toolkit";
4
5
  import * as G from "graphql";
5
- import { TypeInfo, visit, visitWithTypeInfo, getNamedType, GraphQLObjectType, isLeafType, GraphQLUnionType, isScalarType as isScalarType$1, getIntrospectionQuery, buildClientSchema, print, parse } from "graphql";
6
+ import { TypeInfo, visit, visitWithTypeInfo, getNamedType, GraphQLObjectType, isLeafType, GraphQLUnionType, isScalarType as isScalarType$1, getIntrospectionQuery, buildClientSchema, print, parse, buildSchema } from "graphql";
6
7
  import set from "lodash.set";
7
8
  import React, { useState, useCallback, useEffect, Fragment, useMemo } from "react";
8
9
  import { getIn, setIn } from "final-form";
9
10
  import { resolveForm, TinaSchema, addNamespaceToSchema, parseURL, validateSchema } from "@tinacms/schema-tools";
10
11
  export { NAMER, resolveForm } from "@tinacms/schema-tools";
11
- import gql$1 from "graphql-tag";
12
12
  import * as yup from "yup";
13
+ import gql$1 from "graphql-tag";
13
14
  import { setEditing, TinaDataContext, EditContext, useEditState } from "@tinacms/sharedctx";
15
+ import { diff } from "@graphql-inspector/core";
14
16
  import { NavLink, useSearchParams, useNavigate, useParams, useLocation, Link, HashRouter, Routes, Route } from "react-router-dom";
15
17
  import { Transition, Menu } from "@headlessui/react";
16
18
  import { useWindowWidth } from "@react-hook/window-size";
@@ -2114,6 +2116,38 @@ const parseRefForBranchName = (ref) => {
2114
2116
  const matches = ref.match(captureBranchName);
2115
2117
  return matches[1];
2116
2118
  };
2119
+ const ListBranchResponse = z.object({
2120
+ name: z.string(),
2121
+ protected: z.boolean(),
2122
+ commit: z.object({ sha: z.string(), url: z.string() })
2123
+ }).array();
2124
+ const IndexStatusResponse = z.object({
2125
+ status: z.union([
2126
+ z.literal("complete"),
2127
+ z.literal("unknown"),
2128
+ z.literal("failed"),
2129
+ z.literal("inprogress")
2130
+ ]).optional(),
2131
+ timestamp: z.number().optional()
2132
+ });
2133
+ async function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
2134
+ const endTime = new Date().getTime() + pollTimeout;
2135
+ const checkCondition = (resolve, reject) => {
2136
+ Promise.resolve(fn()).then((result) => {
2137
+ const now = new Date().getTime();
2138
+ if (result.done) {
2139
+ resolve(result.data);
2140
+ } else if (now < endTime) {
2141
+ setTimeout(checkCondition, pollInterval, resolve, reject);
2142
+ } else {
2143
+ reject(new Error("AsyncPoller: reached timeout"));
2144
+ }
2145
+ }).catch((err) => {
2146
+ reject(err);
2147
+ });
2148
+ };
2149
+ return new Promise(checkCondition);
2150
+ }
2117
2151
  class Client {
2118
2152
  constructor({ tokenStorage = "MEMORY", ...options }) {
2119
2153
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P;
@@ -2431,12 +2465,64 @@ mutation addPendingDocumentMutation(
2431
2465
  return null;
2432
2466
  }
2433
2467
  }
2468
+ async waitForIndexStatus({ ref }) {
2469
+ try {
2470
+ const result = await asyncPoll(async () => {
2471
+ try {
2472
+ const result2 = await this.getIndexStatus({ ref });
2473
+ if (!(result2.status === "inprogress" || result2.status === "unknown")) {
2474
+ return Promise.resolve({
2475
+ done: true,
2476
+ data: result2
2477
+ });
2478
+ } else {
2479
+ return Promise.resolve({
2480
+ done: false
2481
+ });
2482
+ }
2483
+ } catch (err) {
2484
+ return Promise.reject(err);
2485
+ }
2486
+ }, 5e3, 9e5);
2487
+ return result;
2488
+ } catch (error) {
2489
+ if (error.message === "AsyncPoller: reached timeout") {
2490
+ console.warn(error);
2491
+ return {
2492
+ status: "timeout"
2493
+ };
2494
+ }
2495
+ throw error;
2496
+ }
2497
+ }
2498
+ async getIndexStatus({ ref }) {
2499
+ const url = `${this.contentApiBase}/db/${this.clientId}/status/${ref}`;
2500
+ const res = await this.fetchWithToken(url);
2501
+ const result = await res.json();
2502
+ const parsedResult = IndexStatusResponse.parse(result);
2503
+ return parsedResult;
2504
+ }
2434
2505
  async listBranches() {
2435
- const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2436
- const res = await this.fetchWithToken(url, {
2437
- method: "GET"
2438
- });
2439
- return res.json();
2506
+ try {
2507
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2508
+ const res = await this.fetchWithToken(url, {
2509
+ method: "GET"
2510
+ });
2511
+ const branches = await res.json();
2512
+ const parsedBranches = ListBranchResponse.parse(branches);
2513
+ const indexStatusPromises = parsedBranches.map(async (branch) => {
2514
+ const indexStatus2 = await this.getIndexStatus({ ref: branch.name });
2515
+ return {
2516
+ ...branch,
2517
+ indexStatus: indexStatus2
2518
+ };
2519
+ });
2520
+ const indexStatus = await Promise.all(indexStatusPromises);
2521
+ return indexStatus;
2522
+ } catch (error) {
2523
+ console.error("There was an error listing branches.", error);
2524
+ throw error;
2525
+ }
2440
2526
  }
2441
2527
  async createBranch({ baseBranch, branchName }) {
2442
2528
  const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
@@ -2538,6 +2624,17 @@ class TinaAdminApi {
2538
2624
  async isAuthenticated() {
2539
2625
  return await this.api.isAuthenticated();
2540
2626
  }
2627
+ async checkGraphqlSchema({ localSchema }) {
2628
+ const schemaFromCloud = await this.api.getSchema();
2629
+ const schema1 = schemaFromCloud;
2630
+ const schema2 = buildSchema(print(localSchema));
2631
+ const diffOutput = await diff(schema1, schema2);
2632
+ if (diffOutput.length > 0) {
2633
+ return false;
2634
+ } else {
2635
+ return true;
2636
+ }
2637
+ }
2541
2638
  fetchCollections() {
2542
2639
  return this.schema.getCollections();
2543
2640
  }
@@ -2867,7 +2964,8 @@ const TinaCloudProvider = (props) => {
2867
2964
  if (branchingEnabled) {
2868
2965
  branchSwitcher = new BranchSwitcherPlugin({
2869
2966
  listBranches: handleListBranches,
2870
- createBranch: handleCreateBranch
2967
+ createBranch: handleCreateBranch,
2968
+ chooseBranch: setCurrentBranch
2871
2969
  });
2872
2970
  cms.plugins.add(branchSwitcher);
2873
2971
  }
@@ -3546,6 +3644,10 @@ var styles = `.tina-tailwind {
3546
3644
  --tw-border-opacity: 1;
3547
3645
  border-color: rgb(225 221 236 / var(--tw-border-opacity));
3548
3646
  }
3647
+ .tina-tailwind .border-gray-100 {
3648
+ --tw-border-opacity: 1;
3649
+ border-color: rgb(237 236 243 / var(--tw-border-opacity));
3650
+ }
3549
3651
  .tina-tailwind .bg-white {
3550
3652
  --tw-bg-opacity: 1;
3551
3653
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -3640,6 +3742,10 @@ var styles = `.tina-tailwind {
3640
3742
  padding-left: 12px;
3641
3743
  padding-right: 12px;
3642
3744
  }
3745
+ .tina-tailwind .py-3 {
3746
+ padding-top: 12px;
3747
+ padding-bottom: 12px;
3748
+ }
3643
3749
  .tina-tailwind .py-5 {
3644
3750
  padding-top: 20px;
3645
3751
  padding-bottom: 20px;
@@ -4876,20 +4982,33 @@ const LogoutPage = () => {
4876
4982
  const PageWrapper = ({
4877
4983
  children
4878
4984
  }) => {
4985
+ var _a, _b;
4986
+ const cms = useCMS();
4987
+ const isLocalMode = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode;
4988
+ const [branchingEnabled, setBranchingEnabled] = React.useState(() => cms.flags.get("branch-switcher"));
4989
+ React.useEffect(() => {
4990
+ cms.events.subscribe("flag:set", ({ key, value }) => {
4991
+ if (key === "branch-switcher") {
4992
+ setBranchingEnabled(value);
4993
+ }
4994
+ });
4995
+ }, [cms.events]);
4879
4996
  return /* @__PURE__ */ React.createElement("div", {
4880
4997
  className: "relative left-0 w-full h-full bg-gradient-to-b from-gray-50/50 to-gray-50 shadow-2xl overflow-y-auto transition-opacity duration-300 ease-out flex flex-col opacity-100"
4881
- }, children);
4998
+ }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React.createElement(BranchBanner, null), children);
4882
4999
  };
4883
5000
  const PageHeader = ({
4884
5001
  isLocalMode,
4885
5002
  children
4886
- }) => /* @__PURE__ */ React.createElement(React.Fragment, null, isLocalMode && /* @__PURE__ */ React.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
4887
- className: "pt-12 px-12"
4888
- }, /* @__PURE__ */ React.createElement("div", {
4889
- className: "w-full mx-auto max-w-screen-xl"
4890
- }, /* @__PURE__ */ React.createElement("div", {
4891
- className: "w-full flex justify-between items-end"
4892
- }, children))));
5003
+ }) => {
5004
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, isLocalMode && /* @__PURE__ */ React.createElement(LocalWarning, null), !isLocalMode && /* @__PURE__ */ React.createElement(BillingWarning, null), /* @__PURE__ */ React.createElement("div", {
5005
+ className: "pt-12 px-12"
5006
+ }, /* @__PURE__ */ React.createElement("div", {
5007
+ className: "w-full mx-auto max-w-screen-xl"
5008
+ }, /* @__PURE__ */ React.createElement("div", {
5009
+ className: "w-full flex justify-between items-end"
5010
+ }, children))));
5011
+ };
4893
5012
  const PageBody = ({
4894
5013
  children
4895
5014
  }) => /* @__PURE__ */ React.createElement("div", {
@@ -5175,7 +5294,7 @@ const CollectionListPage = () => {
5175
5294
  }
5176
5295
  }, (collection, _loading, reFetchCollection, collectionExtra) => {
5177
5296
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
5178
- const totalCount = collection.documents.totalCount;
5297
+ collection.documents.totalCount;
5179
5298
  const documents = collection.documents.edges;
5180
5299
  const admin = cms.api.admin;
5181
5300
  const pageInfo = collection.documents.pageInfo;
@@ -5284,7 +5403,7 @@ const CollectionListPage = () => {
5284
5403
  setSortOrder(val.order);
5285
5404
  }
5286
5405
  }
5287
- })), /* @__PURE__ */ React.createElement("div", {
5406
+ })), /* @__PURE__ */ React.createElement("form", {
5288
5407
  className: "flex flex-wrap gap-4 items-end"
5289
5408
  }, /* @__PURE__ */ React.createElement("div", {
5290
5409
  className: "flex flex-shrink-0 flex-col gap-2 items-start"
@@ -5315,6 +5434,9 @@ const CollectionListPage = () => {
5315
5434
  ...old,
5316
5435
  filterField: val
5317
5436
  }));
5437
+ if (!val) {
5438
+ reFetchCollection();
5439
+ }
5318
5440
  }
5319
5441
  }
5320
5442
  })), showStartsWith && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
@@ -5351,7 +5473,7 @@ const CollectionListPage = () => {
5351
5473
  onChange: (e) => {
5352
5474
  setVars((old) => ({
5353
5475
  ...old,
5354
- after: e.format(),
5476
+ after: typeof e.format === "function" ? e.format() : "",
5355
5477
  booleanEquals: null,
5356
5478
  startsWith: ""
5357
5479
  }));
@@ -5369,7 +5491,7 @@ const CollectionListPage = () => {
5369
5491
  onChange: (e) => {
5370
5492
  setVars((old) => ({
5371
5493
  ...old,
5372
- before: e.format(),
5494
+ before: typeof e.format === "function" ? e.format() : "",
5373
5495
  booleanEquals: null,
5374
5496
  startsWith: ""
5375
5497
  }));
@@ -5403,7 +5525,8 @@ const CollectionListPage = () => {
5403
5525
  setPrevCursors([]);
5404
5526
  reFetchCollection();
5405
5527
  },
5406
- variant: "primary"
5528
+ variant: "primary",
5529
+ type: "submit"
5407
5530
  }, "Search", " ", /* @__PURE__ */ React.createElement(BiSearch, {
5408
5531
  className: "w-5 h-full ml-1.5 opacity-70"
5409
5532
  })), (vars.startsWith || vars.after || vars.before || vars.booleanEquals) && /* @__PURE__ */ React.createElement(Button, {
@@ -5433,7 +5556,7 @@ const CollectionListPage = () => {
5433
5556
  templates: collection.templates
5434
5557
  })))), /* @__PURE__ */ React.createElement(PageBody, null, /* @__PURE__ */ React.createElement("div", {
5435
5558
  className: "w-full mx-auto max-w-screen-xl"
5436
- }, totalCount > 0 && /* @__PURE__ */ React.createElement("table", {
5559
+ }, documents.length > 0 ? /* @__PURE__ */ React.createElement("table", {
5437
5560
  className: "table-auto shadow bg-white border-b border-gray-200 w-full max-w-full rounded-lg"
5438
5561
  }, /* @__PURE__ */ React.createElement("tbody", {
5439
5562
  className: "divide-y divide-gray-150"
@@ -5531,7 +5654,7 @@ const CollectionListPage = () => {
5531
5654
  }
5532
5655
  ].filter(Boolean)
5533
5656
  })));
5534
- }))), /* @__PURE__ */ React.createElement("div", {
5657
+ }))) : /* @__PURE__ */ React.createElement(NoDocumentsPlaceholder, null), /* @__PURE__ */ React.createElement("div", {
5535
5658
  className: "pt-4"
5536
5659
  }, /* @__PURE__ */ React.createElement(CursorPaginator, {
5537
5660
  variant: "white",
@@ -5554,6 +5677,13 @@ const CollectionListPage = () => {
5554
5677
  });
5555
5678
  });
5556
5679
  };
5680
+ const NoDocumentsPlaceholder = () => {
5681
+ return /* @__PURE__ */ React.createElement("div", {
5682
+ className: "text-center px-5 py-3 flex flex-col items-center justify-center shadow border border-gray-100 bg-gray-50 border-b border-gray-200 w-full max-w-full rounded-lg"
5683
+ }, /* @__PURE__ */ React.createElement("p", {
5684
+ className: "text-base italic font-medium text-gray-300"
5685
+ }, "No documents found."));
5686
+ };
5557
5687
  const DeleteModal = ({ close: close2, deleteFunc, filename }) => {
5558
5688
  return /* @__PURE__ */ React.createElement(Modal, null, /* @__PURE__ */ React.createElement(PopupModal, null, /* @__PURE__ */ React.createElement(ModalHeader, {
5559
5689
  close: close2
@@ -6019,9 +6149,30 @@ const PreviewInner = ({ preview, config }) => {
6019
6149
  ...config
6020
6150
  });
6021
6151
  };
6152
+ const CheckSchema = ({
6153
+ schemaJson,
6154
+ children
6155
+ }) => {
6156
+ const cms = useCMS();
6157
+ const api = new TinaAdminApi(cms);
6158
+ const url = api.api.contentApiUrl;
6159
+ useEffect(() => {
6160
+ if (schemaJson && cms) {
6161
+ api.checkGraphqlSchema({
6162
+ localSchema: schemaJson
6163
+ }).then((x) => {
6164
+ if (x === false) {
6165
+ cms.alerts.error("GraphQL Schema Mismatch. Editing may not work. If you just switched branches, try going back to the previous branch");
6166
+ }
6167
+ });
6168
+ }
6169
+ }, [cms, JSON.stringify(schemaJson || {}), url]);
6170
+ return children;
6171
+ };
6022
6172
  const TinaAdmin = ({
6023
6173
  preview,
6024
- config
6174
+ config,
6175
+ schemaJson
6025
6176
  }) => {
6026
6177
  const isSSR2 = typeof window === "undefined";
6027
6178
  const { edit } = useEditState();
@@ -6032,9 +6183,18 @@ const TinaAdmin = ({
6032
6183
  return /* @__PURE__ */ React.createElement(Layout, null, /* @__PURE__ */ React.createElement(LoginPage, null));
6033
6184
  }
6034
6185
  return /* @__PURE__ */ React.createElement(GetCMS, null, (cms) => {
6186
+ var _a, _b, _c;
6035
6187
  const isTinaAdminEnabled = cms.flags.get("tina-admin") === false ? false : true;
6036
6188
  if (isTinaAdminEnabled) {
6037
- return /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(SetPreviewFlag, {
6189
+ const tinaClient = (_a = cms.api) == null ? void 0 : _a.tina;
6190
+ const collectionWithRouter = (_c = (_b = tinaClient == null ? void 0 : tinaClient.schema) == null ? void 0 : _b.config) == null ? void 0 : _c.collections.find((x) => {
6191
+ var _a2;
6192
+ return typeof ((_a2 = x == null ? void 0 : x.ui) == null ? void 0 : _a2.router) === "function";
6193
+ });
6194
+ const hasRouter = Boolean(collectionWithRouter);
6195
+ return /* @__PURE__ */ React.createElement(CheckSchema, {
6196
+ schemaJson
6197
+ }, /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(SetPreviewFlag, {
6038
6198
  preview,
6039
6199
  cms
6040
6200
  }), /* @__PURE__ */ React.createElement(Routes, null, preview && /* @__PURE__ */ React.createElement(Route, {
@@ -6076,11 +6236,11 @@ const TinaAdmin = ({
6076
6236
  }), /* @__PURE__ */ React.createElement(Route, {
6077
6237
  path: "/",
6078
6238
  element: /* @__PURE__ */ React.createElement(MaybeRedirectToPreview, {
6079
- redirect: !!preview
6239
+ redirect: !!preview && hasRouter
6080
6240
  }, /* @__PURE__ */ React.createElement(DefaultWrapper, {
6081
6241
  cms
6082
6242
  }, /* @__PURE__ */ React.createElement(DashboardPage, null)))
6083
- })));
6243
+ }))));
6084
6244
  } else {
6085
6245
  return /* @__PURE__ */ React.createElement(Layout, null, /* @__PURE__ */ React.createElement(HashRouter, null, /* @__PURE__ */ React.createElement(Routes, null, /* @__PURE__ */ React.createElement(Route, {
6086
6246
  path: "logout",
@@ -6127,4 +6287,4 @@ const defineStaticConfig = (config) => {
6127
6287
  return config;
6128
6288
  };
6129
6289
  const defineConfig = defineStaticConfig;
6130
- export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, RouteMappingPlugin, TinaAdmin, TinaAdminApi, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, TinaDataProvider, assertShape, createClient, TinaCMSProvider2 as default, defineConfig, defineLegacyConfig, defineSchema, defineStaticConfig, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useGraphqlForms, useTinaAuthRedirect };
6290
+ export { AuthWallInner, Client, DEFAULT_LOCAL_TINA_GQL_SERVER_URL, LocalClient, RouteMappingPlugin, TinaAdmin, TinaAdminApi, TinaCMSProvider2, TinaCloudAuthWall, TinaCloudProvider, TinaDataProvider, assertShape, asyncPoll, createClient, TinaCMSProvider2 as default, defineConfig, defineLegacyConfig, defineSchema, defineStaticConfig, getStaticPropsForTina, gql, safeAssertShape, staticRequest, useDocumentCreatorPlugin, useGraphqlForms, useTinaAuthRedirect };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("final-form"), require("@tinacms/schema-tools"), require("graphql-tag"), require("yup"), require("@tinacms/sharedctx"), require("react-router-dom"), require("@headlessui/react"), require("@react-hook/window-size")) : typeof define === "function" && define.amd ? define(["exports", "@tinacms/toolkit", "graphql", "lodash.set", "react", "final-form", "@tinacms/schema-tools", "graphql-tag", "yup", "@tinacms/sharedctx", "react-router-dom", "@headlessui/react", "@react-hook/window-size"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
3
- })(this, function(exports2, toolkit, G, set, React, finalForm, schemaTools, gql$1, yup, sharedctx, reactRouterDom, react, windowSize) {
2
+ typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("zod"), require("@tinacms/toolkit"), require("graphql"), require("lodash.set"), require("react"), require("final-form"), require("@tinacms/schema-tools"), require("yup"), require("graphql-tag"), require("@tinacms/sharedctx"), require("@graphql-inspector/core"), require("react-router-dom"), require("@headlessui/react"), require("@react-hook/window-size")) : typeof define === "function" && define.amd ? define(["exports", "zod", "@tinacms/toolkit", "graphql", "lodash.set", "react", "final-form", "@tinacms/schema-tools", "yup", "graphql-tag", "@tinacms/sharedctx", "@graphql-inspector/core", "react-router-dom", "@headlessui/react", "@react-hook/window-size"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.tinacms = {}, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP, global.NOOP));
3
+ })(this, function(exports2, zod, toolkit, G, set, React, finalForm, schemaTools, yup, gql$1, sharedctx, core, reactRouterDom, react, windowSize) {
4
4
  "use strict";
5
5
  function _interopDefaultLegacy(e) {
6
6
  return e && typeof e === "object" && "default" in e ? e : { "default": e };
@@ -28,8 +28,8 @@
28
28
  var G__namespace = /* @__PURE__ */ _interopNamespace(G);
29
29
  var set__default = /* @__PURE__ */ _interopDefaultLegacy(set);
30
30
  var React__default = /* @__PURE__ */ _interopDefaultLegacy(React);
31
- var gql__default = /* @__PURE__ */ _interopDefaultLegacy(gql$1);
32
31
  var yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
32
+ var gql__default = /* @__PURE__ */ _interopDefaultLegacy(gql$1);
33
33
  function popupWindow(url, title, window2, w, h) {
34
34
  const y = window2.top.outerHeight / 2 + window2.top.screenY - h / 2;
35
35
  const x = window2.top.outerWidth / 2 + window2.top.screenX - w / 2;
@@ -2130,6 +2130,38 @@
2130
2130
  const matches = ref.match(captureBranchName);
2131
2131
  return matches[1];
2132
2132
  };
2133
+ const ListBranchResponse = zod.z.object({
2134
+ name: zod.z.string(),
2135
+ protected: zod.z.boolean(),
2136
+ commit: zod.z.object({ sha: zod.z.string(), url: zod.z.string() })
2137
+ }).array();
2138
+ const IndexStatusResponse = zod.z.object({
2139
+ status: zod.z.union([
2140
+ zod.z.literal("complete"),
2141
+ zod.z.literal("unknown"),
2142
+ zod.z.literal("failed"),
2143
+ zod.z.literal("inprogress")
2144
+ ]).optional(),
2145
+ timestamp: zod.z.number().optional()
2146
+ });
2147
+ async function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
2148
+ const endTime = new Date().getTime() + pollTimeout;
2149
+ const checkCondition = (resolve, reject) => {
2150
+ Promise.resolve(fn()).then((result) => {
2151
+ const now = new Date().getTime();
2152
+ if (result.done) {
2153
+ resolve(result.data);
2154
+ } else if (now < endTime) {
2155
+ setTimeout(checkCondition, pollInterval, resolve, reject);
2156
+ } else {
2157
+ reject(new Error("AsyncPoller: reached timeout"));
2158
+ }
2159
+ }).catch((err) => {
2160
+ reject(err);
2161
+ });
2162
+ };
2163
+ return new Promise(checkCondition);
2164
+ }
2133
2165
  class Client {
2134
2166
  constructor({ tokenStorage = "MEMORY", ...options }) {
2135
2167
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P;
@@ -2447,12 +2479,64 @@ mutation addPendingDocumentMutation(
2447
2479
  return null;
2448
2480
  }
2449
2481
  }
2482
+ async waitForIndexStatus({ ref }) {
2483
+ try {
2484
+ const result = await asyncPoll(async () => {
2485
+ try {
2486
+ const result2 = await this.getIndexStatus({ ref });
2487
+ if (!(result2.status === "inprogress" || result2.status === "unknown")) {
2488
+ return Promise.resolve({
2489
+ done: true,
2490
+ data: result2
2491
+ });
2492
+ } else {
2493
+ return Promise.resolve({
2494
+ done: false
2495
+ });
2496
+ }
2497
+ } catch (err) {
2498
+ return Promise.reject(err);
2499
+ }
2500
+ }, 5e3, 9e5);
2501
+ return result;
2502
+ } catch (error) {
2503
+ if (error.message === "AsyncPoller: reached timeout") {
2504
+ console.warn(error);
2505
+ return {
2506
+ status: "timeout"
2507
+ };
2508
+ }
2509
+ throw error;
2510
+ }
2511
+ }
2512
+ async getIndexStatus({ ref }) {
2513
+ const url = `${this.contentApiBase}/db/${this.clientId}/status/${ref}`;
2514
+ const res = await this.fetchWithToken(url);
2515
+ const result = await res.json();
2516
+ const parsedResult = IndexStatusResponse.parse(result);
2517
+ return parsedResult;
2518
+ }
2450
2519
  async listBranches() {
2451
- const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2452
- const res = await this.fetchWithToken(url, {
2453
- method: "GET"
2454
- });
2455
- return res.json();
2520
+ try {
2521
+ const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
2522
+ const res = await this.fetchWithToken(url, {
2523
+ method: "GET"
2524
+ });
2525
+ const branches = await res.json();
2526
+ const parsedBranches = ListBranchResponse.parse(branches);
2527
+ const indexStatusPromises = parsedBranches.map(async (branch) => {
2528
+ const indexStatus2 = await this.getIndexStatus({ ref: branch.name });
2529
+ return {
2530
+ ...branch,
2531
+ indexStatus: indexStatus2
2532
+ };
2533
+ });
2534
+ const indexStatus = await Promise.all(indexStatusPromises);
2535
+ return indexStatus;
2536
+ } catch (error) {
2537
+ console.error("There was an error listing branches.", error);
2538
+ throw error;
2539
+ }
2456
2540
  }
2457
2541
  async createBranch({ baseBranch, branchName }) {
2458
2542
  const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
@@ -2554,6 +2638,17 @@ mutation addPendingDocumentMutation(
2554
2638
  async isAuthenticated() {
2555
2639
  return await this.api.isAuthenticated();
2556
2640
  }
2641
+ async checkGraphqlSchema({ localSchema }) {
2642
+ const schemaFromCloud = await this.api.getSchema();
2643
+ const schema1 = schemaFromCloud;
2644
+ const schema2 = G.buildSchema(G.print(localSchema));
2645
+ const diffOutput = await core.diff(schema1, schema2);
2646
+ if (diffOutput.length > 0) {
2647
+ return false;
2648
+ } else {
2649
+ return true;
2650
+ }
2651
+ }
2557
2652
  fetchCollections() {
2558
2653
  return this.schema.getCollections();
2559
2654
  }
@@ -2883,7 +2978,8 @@ mutation addPendingDocumentMutation(
2883
2978
  if (branchingEnabled) {
2884
2979
  branchSwitcher = new toolkit.BranchSwitcherPlugin({
2885
2980
  listBranches: handleListBranches,
2886
- createBranch: handleCreateBranch
2981
+ createBranch: handleCreateBranch,
2982
+ chooseBranch: setCurrentBranch
2887
2983
  });
2888
2984
  cms.plugins.add(branchSwitcher);
2889
2985
  }
@@ -3562,6 +3658,10 @@ mutation addPendingDocumentMutation(
3562
3658
  --tw-border-opacity: 1;
3563
3659
  border-color: rgb(225 221 236 / var(--tw-border-opacity));
3564
3660
  }
3661
+ .tina-tailwind .border-gray-100 {
3662
+ --tw-border-opacity: 1;
3663
+ border-color: rgb(237 236 243 / var(--tw-border-opacity));
3664
+ }
3565
3665
  .tina-tailwind .bg-white {
3566
3666
  --tw-bg-opacity: 1;
3567
3667
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -3656,6 +3756,10 @@ mutation addPendingDocumentMutation(
3656
3756
  padding-left: 12px;
3657
3757
  padding-right: 12px;
3658
3758
  }
3759
+ .tina-tailwind .py-3 {
3760
+ padding-top: 12px;
3761
+ padding-bottom: 12px;
3762
+ }
3659
3763
  .tina-tailwind .py-5 {
3660
3764
  padding-top: 20px;
3661
3765
  padding-bottom: 20px;
@@ -4892,20 +4996,33 @@ This will work when developing locally but NOT when deployed to production.
4892
4996
  const PageWrapper = ({
4893
4997
  children
4894
4998
  }) => {
4999
+ var _a, _b;
5000
+ const cms = toolkit.useCMS();
5001
+ const isLocalMode = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode;
5002
+ const [branchingEnabled, setBranchingEnabled] = React__default["default"].useState(() => cms.flags.get("branch-switcher"));
5003
+ React__default["default"].useEffect(() => {
5004
+ cms.events.subscribe("flag:set", ({ key, value }) => {
5005
+ if (key === "branch-switcher") {
5006
+ setBranchingEnabled(value);
5007
+ }
5008
+ });
5009
+ }, [cms.events]);
4895
5010
  return /* @__PURE__ */ React__default["default"].createElement("div", {
4896
5011
  className: "relative left-0 w-full h-full bg-gradient-to-b from-gray-50/50 to-gray-50 shadow-2xl overflow-y-auto transition-opacity duration-300 ease-out flex flex-col opacity-100"
4897
- }, children);
5012
+ }, branchingEnabled && !isLocalMode && /* @__PURE__ */ React__default["default"].createElement(toolkit.BranchBanner, null), children);
4898
5013
  };
4899
5014
  const PageHeader = ({
4900
5015
  isLocalMode,
4901
5016
  children
4902
- }) => /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, isLocalMode && /* @__PURE__ */ React__default["default"].createElement(toolkit.LocalWarning, null), !isLocalMode && /* @__PURE__ */ React__default["default"].createElement(toolkit.BillingWarning, null), /* @__PURE__ */ React__default["default"].createElement("div", {
4903
- className: "pt-12 px-12"
4904
- }, /* @__PURE__ */ React__default["default"].createElement("div", {
4905
- className: "w-full mx-auto max-w-screen-xl"
4906
- }, /* @__PURE__ */ React__default["default"].createElement("div", {
4907
- className: "w-full flex justify-between items-end"
4908
- }, children))));
5017
+ }) => {
5018
+ return /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, isLocalMode && /* @__PURE__ */ React__default["default"].createElement(toolkit.LocalWarning, null), !isLocalMode && /* @__PURE__ */ React__default["default"].createElement(toolkit.BillingWarning, null), /* @__PURE__ */ React__default["default"].createElement("div", {
5019
+ className: "pt-12 px-12"
5020
+ }, /* @__PURE__ */ React__default["default"].createElement("div", {
5021
+ className: "w-full mx-auto max-w-screen-xl"
5022
+ }, /* @__PURE__ */ React__default["default"].createElement("div", {
5023
+ className: "w-full flex justify-between items-end"
5024
+ }, children))));
5025
+ };
4909
5026
  const PageBody = ({
4910
5027
  children
4911
5028
  }) => /* @__PURE__ */ React__default["default"].createElement("div", {
@@ -5191,7 +5308,7 @@ This will work when developing locally but NOT when deployed to production.
5191
5308
  }
5192
5309
  }, (collection, _loading, reFetchCollection, collectionExtra) => {
5193
5310
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
5194
- const totalCount = collection.documents.totalCount;
5311
+ collection.documents.totalCount;
5195
5312
  const documents = collection.documents.edges;
5196
5313
  const admin = cms.api.admin;
5197
5314
  const pageInfo = collection.documents.pageInfo;
@@ -5300,7 +5417,7 @@ This will work when developing locally but NOT when deployed to production.
5300
5417
  setSortOrder(val.order);
5301
5418
  }
5302
5419
  }
5303
- })), /* @__PURE__ */ React__default["default"].createElement("div", {
5420
+ })), /* @__PURE__ */ React__default["default"].createElement("form", {
5304
5421
  className: "flex flex-wrap gap-4 items-end"
5305
5422
  }, /* @__PURE__ */ React__default["default"].createElement("div", {
5306
5423
  className: "flex flex-shrink-0 flex-col gap-2 items-start"
@@ -5331,6 +5448,9 @@ This will work when developing locally but NOT when deployed to production.
5331
5448
  ...old,
5332
5449
  filterField: val
5333
5450
  }));
5451
+ if (!val) {
5452
+ reFetchCollection();
5453
+ }
5334
5454
  }
5335
5455
  }
5336
5456
  })), showStartsWith && /* @__PURE__ */ React__default["default"].createElement(React__default["default"].Fragment, null, /* @__PURE__ */ React__default["default"].createElement("div", {
@@ -5367,7 +5487,7 @@ This will work when developing locally but NOT when deployed to production.
5367
5487
  onChange: (e) => {
5368
5488
  setVars((old) => ({
5369
5489
  ...old,
5370
- after: e.format(),
5490
+ after: typeof e.format === "function" ? e.format() : "",
5371
5491
  booleanEquals: null,
5372
5492
  startsWith: ""
5373
5493
  }));
@@ -5385,7 +5505,7 @@ This will work when developing locally but NOT when deployed to production.
5385
5505
  onChange: (e) => {
5386
5506
  setVars((old) => ({
5387
5507
  ...old,
5388
- before: e.format(),
5508
+ before: typeof e.format === "function" ? e.format() : "",
5389
5509
  booleanEquals: null,
5390
5510
  startsWith: ""
5391
5511
  }));
@@ -5419,7 +5539,8 @@ This will work when developing locally but NOT when deployed to production.
5419
5539
  setPrevCursors([]);
5420
5540
  reFetchCollection();
5421
5541
  },
5422
- variant: "primary"
5542
+ variant: "primary",
5543
+ type: "submit"
5423
5544
  }, "Search", " ", /* @__PURE__ */ React__default["default"].createElement(BiSearch, {
5424
5545
  className: "w-5 h-full ml-1.5 opacity-70"
5425
5546
  })), (vars.startsWith || vars.after || vars.before || vars.booleanEquals) && /* @__PURE__ */ React__default["default"].createElement(toolkit.Button, {
@@ -5449,7 +5570,7 @@ This will work when developing locally but NOT when deployed to production.
5449
5570
  templates: collection.templates
5450
5571
  })))), /* @__PURE__ */ React__default["default"].createElement(PageBody, null, /* @__PURE__ */ React__default["default"].createElement("div", {
5451
5572
  className: "w-full mx-auto max-w-screen-xl"
5452
- }, totalCount > 0 && /* @__PURE__ */ React__default["default"].createElement("table", {
5573
+ }, documents.length > 0 ? /* @__PURE__ */ React__default["default"].createElement("table", {
5453
5574
  className: "table-auto shadow bg-white border-b border-gray-200 w-full max-w-full rounded-lg"
5454
5575
  }, /* @__PURE__ */ React__default["default"].createElement("tbody", {
5455
5576
  className: "divide-y divide-gray-150"
@@ -5547,7 +5668,7 @@ This will work when developing locally but NOT when deployed to production.
5547
5668
  }
5548
5669
  ].filter(Boolean)
5549
5670
  })));
5550
- }))), /* @__PURE__ */ React__default["default"].createElement("div", {
5671
+ }))) : /* @__PURE__ */ React__default["default"].createElement(NoDocumentsPlaceholder, null), /* @__PURE__ */ React__default["default"].createElement("div", {
5551
5672
  className: "pt-4"
5552
5673
  }, /* @__PURE__ */ React__default["default"].createElement(toolkit.CursorPaginator, {
5553
5674
  variant: "white",
@@ -5570,6 +5691,13 @@ This will work when developing locally but NOT when deployed to production.
5570
5691
  });
5571
5692
  });
5572
5693
  };
5694
+ const NoDocumentsPlaceholder = () => {
5695
+ return /* @__PURE__ */ React__default["default"].createElement("div", {
5696
+ className: "text-center px-5 py-3 flex flex-col items-center justify-center shadow border border-gray-100 bg-gray-50 border-b border-gray-200 w-full max-w-full rounded-lg"
5697
+ }, /* @__PURE__ */ React__default["default"].createElement("p", {
5698
+ className: "text-base italic font-medium text-gray-300"
5699
+ }, "No documents found."));
5700
+ };
5573
5701
  const DeleteModal = ({ close: close2, deleteFunc, filename }) => {
5574
5702
  return /* @__PURE__ */ React__default["default"].createElement(toolkit.Modal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.PopupModal, null, /* @__PURE__ */ React__default["default"].createElement(toolkit.ModalHeader, {
5575
5703
  close: close2
@@ -6035,9 +6163,30 @@ This will work when developing locally but NOT when deployed to production.
6035
6163
  ...config
6036
6164
  });
6037
6165
  };
6166
+ const CheckSchema = ({
6167
+ schemaJson,
6168
+ children
6169
+ }) => {
6170
+ const cms = toolkit.useCMS();
6171
+ const api = new TinaAdminApi(cms);
6172
+ const url = api.api.contentApiUrl;
6173
+ React.useEffect(() => {
6174
+ if (schemaJson && cms) {
6175
+ api.checkGraphqlSchema({
6176
+ localSchema: schemaJson
6177
+ }).then((x) => {
6178
+ if (x === false) {
6179
+ cms.alerts.error("GraphQL Schema Mismatch. Editing may not work. If you just switched branches, try going back to the previous branch");
6180
+ }
6181
+ });
6182
+ }
6183
+ }, [cms, JSON.stringify(schemaJson || {}), url]);
6184
+ return children;
6185
+ };
6038
6186
  const TinaAdmin = ({
6039
6187
  preview,
6040
- config
6188
+ config,
6189
+ schemaJson
6041
6190
  }) => {
6042
6191
  const isSSR2 = typeof window === "undefined";
6043
6192
  const { edit } = sharedctx.useEditState();
@@ -6048,9 +6197,18 @@ This will work when developing locally but NOT when deployed to production.
6048
6197
  return /* @__PURE__ */ React__default["default"].createElement(Layout, null, /* @__PURE__ */ React__default["default"].createElement(LoginPage, null));
6049
6198
  }
6050
6199
  return /* @__PURE__ */ React__default["default"].createElement(GetCMS, null, (cms) => {
6200
+ var _a, _b, _c;
6051
6201
  const isTinaAdminEnabled = cms.flags.get("tina-admin") === false ? false : true;
6052
6202
  if (isTinaAdminEnabled) {
6053
- return /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.HashRouter, null, /* @__PURE__ */ React__default["default"].createElement(SetPreviewFlag, {
6203
+ const tinaClient = (_a = cms.api) == null ? void 0 : _a.tina;
6204
+ const collectionWithRouter = (_c = (_b = tinaClient == null ? void 0 : tinaClient.schema) == null ? void 0 : _b.config) == null ? void 0 : _c.collections.find((x) => {
6205
+ var _a2;
6206
+ return typeof ((_a2 = x == null ? void 0 : x.ui) == null ? void 0 : _a2.router) === "function";
6207
+ });
6208
+ const hasRouter = Boolean(collectionWithRouter);
6209
+ return /* @__PURE__ */ React__default["default"].createElement(CheckSchema, {
6210
+ schemaJson
6211
+ }, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.HashRouter, null, /* @__PURE__ */ React__default["default"].createElement(SetPreviewFlag, {
6054
6212
  preview,
6055
6213
  cms
6056
6214
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Routes, null, preview && /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
@@ -6092,11 +6250,11 @@ This will work when developing locally but NOT when deployed to production.
6092
6250
  }), /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
6093
6251
  path: "/",
6094
6252
  element: /* @__PURE__ */ React__default["default"].createElement(MaybeRedirectToPreview, {
6095
- redirect: !!preview
6253
+ redirect: !!preview && hasRouter
6096
6254
  }, /* @__PURE__ */ React__default["default"].createElement(DefaultWrapper, {
6097
6255
  cms
6098
6256
  }, /* @__PURE__ */ React__default["default"].createElement(DashboardPage, null)))
6099
- })));
6257
+ }))));
6100
6258
  } else {
6101
6259
  return /* @__PURE__ */ React__default["default"].createElement(Layout, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.HashRouter, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Routes, null, /* @__PURE__ */ React__default["default"].createElement(reactRouterDom.Route, {
6102
6260
  path: "logout",
@@ -6173,6 +6331,7 @@ This will work when developing locally but NOT when deployed to production.
6173
6331
  exports2.TinaCloudProvider = TinaCloudProvider;
6174
6332
  exports2.TinaDataProvider = TinaDataProvider;
6175
6333
  exports2.assertShape = assertShape;
6334
+ exports2.asyncPoll = asyncPoll;
6176
6335
  exports2.createClient = createClient;
6177
6336
  exports2["default"] = TinaCMSProvider2;
6178
6337
  exports2.defineConfig = defineConfig;
@@ -1,6 +1,3 @@
1
- /**
2
-
3
- */
4
1
  import { TokenObject } from '../auth/authenticate';
5
2
  import { BranchData, EventBus } from '@tinacms/toolkit';
6
3
  import { DocumentNode, GraphQLSchema } from 'graphql';
@@ -24,6 +21,90 @@ interface ServerOptions {
24
21
  tinaioConfig?: TinaIOConfig;
25
22
  tokenStorage?: 'MEMORY' | 'LOCAL_STORAGE' | 'CUSTOM';
26
23
  }
24
+ /**
25
+ * The function you pass to `asyncPoll` should return a promise
26
+ * that resolves with object that satisfies this interface.
27
+ *
28
+ * The `done` property indicates to the async poller whether to
29
+ * continue polling or not.
30
+ *
31
+ * When done is `true` that means you've got what you need
32
+ * and the poller will resolve with `data`.
33
+ *
34
+ * When done is `false` taht means you don't have what you need
35
+ * and the poller will continue polling.
36
+ */
37
+ export interface AsyncData<T> {
38
+ done: boolean;
39
+ data?: T;
40
+ }
41
+ /**
42
+ * Your custom function you provide to the async poller should
43
+ * satisfy this interface. Your function returns a promise that
44
+ * resolves with `AsyncData` to indicate to the poller whether
45
+ * you have what you need or we should continue polling.
46
+ */
47
+ export interface AsyncFunction<T> extends Function {
48
+ (): PromiseLike<AsyncData<T>>;
49
+ }
50
+ /**
51
+ * How to repeatedly call an async function until get a desired result.
52
+ *
53
+ * Inspired by the following gist:
54
+ * https://gist.github.com/twmbx/2321921670c7e95f6fad164fbdf3170e#gistcomment-3053587
55
+ * https://davidwalsh.name/javascript-polling
56
+ *
57
+ * Usage:
58
+ asyncPoll(
59
+ async (): Promise<AsyncData<any>> => {
60
+ try {
61
+ const result = await getYourAsyncResult();
62
+ if (result.isWhatYouWant) {
63
+ return Promise.resolve({
64
+ done: true,
65
+ data: result,
66
+ });
67
+ } else {
68
+ return Promise.resolve({
69
+ done: false
70
+ });
71
+ }
72
+ } catch (err) {
73
+ return Promise.reject(err);
74
+ }
75
+ },
76
+ 500, // interval
77
+ 15000, // timeout
78
+ );
79
+ */
80
+ export declare function asyncPoll<T>(
81
+ /**
82
+ * Function to call periodically until it resolves or rejects.
83
+ *
84
+ * It should resolve as soon as possible indicating if it found
85
+ * what it was looking for or not. If not then it will be reinvoked
86
+ * after the `pollInterval` if we haven't timed out.
87
+ *
88
+ * Rejections will stop the polling and be propagated.
89
+ */
90
+ fn: AsyncFunction<T>,
91
+ /**
92
+ * Milliseconds to wait before attempting to resolve the promise again.
93
+ * The promise won't be called concurrently. This is the wait period
94
+ * after the promise has resolved/rejected before trying again for a
95
+ * successful resolve so long as we haven't timed out.
96
+ *
97
+ * Default 5 seconds.
98
+ */
99
+ pollInterval?: number,
100
+ /**
101
+ * Max time to keep polling to receive a successful resolved response.
102
+ * If the promise never resolves before the timeout then this method
103
+ * rejects with a timeout error.
104
+ *
105
+ * Default 30 seconds.
106
+ */
107
+ pollTimeout?: number): Promise<T>;
27
108
  export declare class Client {
28
109
  onLogin?: OnLoginFunc;
29
110
  onLogout?: () => Promise<void>;
@@ -121,7 +202,27 @@ export declare class Client {
121
202
  delinquencyDate: number;
122
203
  billingState: 'current' | 'late' | 'delinquent';
123
204
  }>;
124
- listBranches(): Promise<any>;
205
+ waitForIndexStatus({ ref }: {
206
+ ref: string;
207
+ }): Promise<any>;
208
+ getIndexStatus({ ref }: {
209
+ ref: string;
210
+ }): Promise<{
211
+ status?: "unknown" | "complete" | "failed" | "inprogress";
212
+ timestamp?: number;
213
+ }>;
214
+ listBranches(): Promise<{
215
+ indexStatus: {
216
+ status?: "unknown" | "complete" | "failed" | "inprogress";
217
+ timestamp?: number;
218
+ };
219
+ name?: string;
220
+ protected?: boolean;
221
+ commit?: {
222
+ url?: string;
223
+ sha?: string;
224
+ };
225
+ }[]>;
125
226
  createBranch({ baseBranch, branchName }: BranchData): Promise<string>;
126
227
  }
127
228
  export declare const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
package/dist/style.css CHANGED
@@ -649,6 +649,10 @@
649
649
  --tw-border-opacity: 1;
650
650
  border-color: rgb(225 221 236 / var(--tw-border-opacity));
651
651
  }
652
+ .tina-tailwind .border-gray-100 {
653
+ --tw-border-opacity: 1;
654
+ border-color: rgb(237 236 243 / var(--tw-border-opacity));
655
+ }
652
656
  .tina-tailwind .bg-white {
653
657
  --tw-bg-opacity: 1;
654
658
  background-color: rgb(255 255 255 / var(--tw-bg-opacity));
@@ -743,6 +747,10 @@
743
747
  padding-left: 12px;
744
748
  padding-right: 12px;
745
749
  }
750
+ .tina-tailwind .py-3 {
751
+ padding-top: 12px;
752
+ padding-bottom: 12px;
753
+ }
746
754
  .tina-tailwind .py-5 {
747
755
  padding-top: 20px;
748
756
  padding-bottom: 20px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinacms",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "main": "dist/index.js",
5
5
  "module": "./dist/index.es.js",
6
6
  "exports": {
@@ -51,13 +51,14 @@
51
51
  "typings": "dist/index.d.ts",
52
52
  "license": "Apache-2.0",
53
53
  "dependencies": {
54
+ "@graphql-inspector/core": "^4.0.0",
54
55
  "@graphql-tools/relay-operation-optimizer": "^6.4.1",
55
56
  "@headlessui/react": "^1.5.0",
56
57
  "@heroicons/react": "^1.0.4",
57
58
  "@react-hook/window-size": "^3.0.7",
58
- "@tinacms/schema-tools": "1.3.0",
59
+ "@tinacms/schema-tools": "1.3.2",
59
60
  "@tinacms/sharedctx": "1.0.1",
60
- "@tinacms/toolkit": "1.3.2",
61
+ "@tinacms/toolkit": "1.3.4",
61
62
  "crypto-js": "^4.0.0",
62
63
  "encoding": "0.1.13",
63
64
  "fetch-ponyfill": "^7.1.0",
@@ -68,7 +69,8 @@
68
69
  "prism-react-renderer": "^1.3.5",
69
70
  "react-icons": "^4.3.1",
70
71
  "react-router-dom": "6",
71
- "yup": "^0.32.0"
72
+ "yup": "^0.32.0",
73
+ "zod": "^3.14.3"
72
74
  },
73
75
  "devDependencies": {
74
76
  "@graphql-tools/utils": "^8.6.1",