tinacms 3.14.2 → 3.14.4

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,9 @@
1
+ import type { TinaCMS } from '@tinacms/toolkit';
1
2
  import React from 'react';
2
3
  export declare const ErrorDialog: (props: {
3
- title: string;
4
+ /** @deprecated Pass the title to `cms.alerts.error` so it shows in the modal header. */
5
+ title?: string;
4
6
  message: string;
5
7
  error: Error;
6
8
  }) => React.JSX.Element;
9
+ export declare const showErrorModal: (title: string, message: string, cms: TinaCMS) => void;
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { useDocumentCreatorPlugin } from './hooks/use-content-creator';
9
9
  export { TinaAdmin } from './admin';
10
10
  export { RouteMappingPlugin } from './admin/plugins/route-mapping';
11
11
  export { TinaAdminApi } from './admin/api';
12
- export { ErrorDialog } from './admin/components/ErrorDialog';
12
+ export { ErrorDialog, showErrorModal } from './admin/components/ErrorDialog';
13
13
  export * from './toolkit';
14
14
  export { Form } from './toolkit/forms/form';
15
15
  export { MdxFieldPluginExtendible } from '@tinacms/toolkit';
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ import React__default, { useState, useCallback, useRef, useEffect, createContext
7
7
  import { createPortal } from "react-dom";
8
8
  import { clsx } from "clsx";
9
9
  import { twMerge } from "tailwind-merge";
10
+ import { CircleAlert, X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, Baseline, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleCheck as CircleCheck$1, CircleIcon, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
10
11
  import { withRef, cn as cn$1, withCn, createPrimitiveElement, withVariants, withProps, PortalBody, useComposedRef as useComposedRef$1 } from "@udecode/cn";
11
12
  import { BoldPlugin, ItalicPlugin, StrikethroughPlugin, UnderlinePlugin, CodePlugin, BasicMarksPlugin } from "@udecode/plate-basic-marks/react";
12
13
  import { BlockquotePlugin } from "@udecode/plate-block-quote/react";
@@ -20,7 +21,6 @@ import { SlashInputPlugin, SlashPlugin } from "@udecode/plate-slash-command/reac
20
21
  import { TablePlugin, TableRowPlugin, useTableCellElement, TableProvider, useTableElement, useTableMergeState, useTableBordersDropdownMenuContentState, TableCellPlugin, TableCellHeaderPlugin } from "@udecode/plate-table/react";
21
22
  import { PlateElement, useReadOnly, useElement, PlateLeaf, useSelected, useFocused, useEditorRef, withRef as withRef$1, useComposedRef, useEditorPlugin, useElementSelector, withHOC, usePluginOption, useRemoveNodeButton, useEditorSelector, ParagraphPlugin, createPlatePlugin, PlateContent, PlateContainer, useEditorState, useMarkToolbarButtonState, useMarkToolbarButton, usePlateEditor, useFormInputProps, useEditorSelection, useEditorReadOnly, useOnClickOutside, useEventEditorValue, Plate } from "@udecode/plate/react";
22
23
  import { isLangSupported, formatCodeBlock, insertEmptyCodeBlock, isCodeBlockEmpty, unwrapCodeBlock, isSelectionAtCodeBlockStart } from "@udecode/plate-code-block";
23
- import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, Baseline, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleAlert, CircleCheck as CircleCheck$1, CircleIcon, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
24
24
  import { Slot } from "@radix-ui/react-slot";
25
25
  import { cva } from "class-variance-authority";
26
26
  import { Command as Command$2 } from "cmdk";
@@ -851,6 +851,12 @@ const PopupModal = ({ className = "", style = {}, ...props }) => /* @__PURE__ */
851
851
  }
852
852
  );
853
853
  const ModalPopup = PopupModal;
854
+ const ErrorModal = ({
855
+ title,
856
+ actions,
857
+ close: close2,
858
+ children
859
+ }) => /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React__default.createElement(CircleAlert, { className: "mr-1 w-6 h-auto inline-block text-red-600" }), " ", title), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose whitespace-pre-wrap" }, children)), /* @__PURE__ */ React__default.createElement(ModalActions, { align: "end" }, actions)));
854
860
  const ERROR_MISSING_CMS = `useCMS could not find an instance of CMS`;
855
861
  const CMSContext = React.createContext(null);
856
862
  function useCMS$1() {
@@ -3788,7 +3794,20 @@ class Form {
3788
3794
  if (field.templates) {
3789
3795
  if (field.list) {
3790
3796
  if (isLastItem) {
3791
- return formOrObjectField;
3797
+ const fieldName = namePath.slice(0, namePathIndex).join(".");
3798
+ if (!fieldName) {
3799
+ return formOrObjectField;
3800
+ }
3801
+ return {
3802
+ ...formOrObjectField,
3803
+ name: fieldName,
3804
+ fields: formOrObjectField.fields.map((field2) => {
3805
+ return {
3806
+ ...field2,
3807
+ name: [fieldName, field2.name].join(".")
3808
+ };
3809
+ })
3810
+ };
3792
3811
  } else {
3793
3812
  const namePathIndexForListItem = namePathIndex + 1;
3794
3813
  const index = namePath[namePathIndexForListItem];
@@ -5757,7 +5776,7 @@ const ImageUpload = React.forwardRef(({ onDrop, onClear, onClick, value, src, lo
5757
5776
  /* @__PURE__ */ React.createElement(
5758
5777
  "button",
5759
5778
  {
5760
- className: "flex-shrink min-w-0 focus-within:shadow-outline focus-within:border-blue-500 rounded outline-none overflow-visible cursor-pointer border-none hover:opacity-60 transition ease-out duration-100",
5779
+ className: "flex-shrink min-w-0 focus-within:shadow-outline focus-within:border-blue-500 rounded outline-none overflow-visible cursor-pointer border-none hover:ring-2 hover:ring-orange-500 transition-shadow ease-in-out duration-200",
5761
5780
  onClick,
5762
5781
  ref
5763
5782
  },
@@ -7533,8 +7552,8 @@ const ImageField = wrapFieldsWithMeta(
7533
7552
  `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
7534
7553
  );
7535
7554
  });
7536
- cms.alerts.error(() => {
7537
- return /* @__PURE__ */ React.createElement(React.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React.createElement("br", null), messages.join(". "), ".");
7555
+ cms.alerts.error(`${messages.join(". ")}.`, {
7556
+ title: "Upload Failed"
7538
7557
  });
7539
7558
  }
7540
7559
  } catch (error) {
@@ -10108,7 +10127,7 @@ let Alerts$1 = class Alerts {
10108
10127
  ...eventsToAlerts
10109
10128
  };
10110
10129
  }
10111
- add(level, message, timeout = 4e3) {
10130
+ add(level, message, timeout = 4e3, title) {
10112
10131
  if (this.suppressed) {
10113
10132
  return () => {
10114
10133
  };
@@ -10117,6 +10136,7 @@ let Alerts$1 = class Alerts {
10117
10136
  level,
10118
10137
  message,
10119
10138
  timeout,
10139
+ title,
10120
10140
  id: `${message}|${Date.now()}`
10121
10141
  };
10122
10142
  this.alerts.set(alert.id, alert);
@@ -10149,8 +10169,11 @@ let Alerts$1 = class Alerts {
10149
10169
  warn(message, timeout) {
10150
10170
  return this.add("warn", message, timeout);
10151
10171
  }
10152
- error(message, timeout) {
10153
- return this.add("error", message, timeout);
10172
+ error(message, options) {
10173
+ if (typeof options === "number") {
10174
+ return this.add("error", message, options);
10175
+ }
10176
+ return this.add("error", message, void 0, options == null ? void 0 : options.title);
10154
10177
  }
10155
10178
  };
10156
10179
  class EventBus {
@@ -12480,8 +12503,8 @@ function MediaPicker({
12480
12503
  `${fileRejection.file.name}: ${fileRejection.errors.map((error) => printError(error)).join(", ")}`
12481
12504
  );
12482
12505
  });
12483
- cms.alerts.error(() => {
12484
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, "Upload Failed. ", /* @__PURE__ */ React__default.createElement("br", null), messages.join(". "), ".");
12506
+ cms.alerts.error(`${messages.join(". ")}.`, {
12507
+ title: "Upload Failed"
12485
12508
  });
12486
12509
  }
12487
12510
  if (mediaItems.length !== 0) {
@@ -14305,7 +14328,7 @@ const FormModal = ({ plugin, close: close2 }) => {
14305
14328
  const name = "tinacms";
14306
14329
  const type = "module";
14307
14330
  const typings = "dist/index.d.ts";
14308
- const version = "3.14.2";
14331
+ const version = "3.14.4";
14309
14332
  const main = "dist/index.js";
14310
14333
  const module$1 = "./dist/index.js";
14311
14334
  const exports$1 = { ".": "./dist/index.js", "./dist/client": { "types": "./dist/client.d.ts", "browser": "./dist/client.browser.js", "default": "./dist/client.js" }, "./react": "./dist/react.js", "./dist/react": "./dist/react.js", "./tina-field": "./dist/tina-field.js", "./dist/tina-field": "./dist/tina-field.js", "./dist/rich-text": "./dist/rich-text/index.js", "./dist/rich-text/static": "./dist/rich-text/static.js", "./dist/rich-text/prism": "./dist/rich-text/prism.js" };
@@ -16615,26 +16638,19 @@ function Alerts2({ alerts }) {
16615
16638
  const AlertMessage = typeof alert.message === "string" ? () => {
16616
16639
  return /* @__PURE__ */ React__default.createElement("p", { className: "text-base mb-3 overflow-y-auto" }, parseUrlsInText(alert.message.toString()));
16617
16640
  } : alert.message;
16618
- return /* @__PURE__ */ React__default.createElement(Modal, { key: alert.id }, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(
16619
- ModalHeader,
16620
- {
16621
- close: () => {
16622
- alerts.dismiss(alert);
16623
- }
16624
- },
16625
- /* @__PURE__ */ React__default.createElement(CircleAlert, { className: "mr-1 w-6 h-auto inline-block text-red-600" }),
16626
- " ",
16627
- "Error"
16628
- ), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose whitespace-pre-wrap" }, /* @__PURE__ */ React__default.createElement(AlertMessage, null))), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
16629
- Button$2,
16641
+ const dismiss = () => {
16642
+ alerts.dismiss(alert);
16643
+ };
16644
+ return /* @__PURE__ */ React__default.createElement(
16645
+ ErrorModal,
16630
16646
  {
16631
- style: { flexGrow: 1 },
16632
- onClick: () => {
16633
- alerts.dismiss(alert);
16634
- }
16647
+ key: alert.id,
16648
+ title: alert.title ?? "Error",
16649
+ close: dismiss,
16650
+ actions: /* @__PURE__ */ React__default.createElement(Button$2, { className: "w-full sm:w-auto", onClick: dismiss }, "Close")
16635
16651
  },
16636
- "Close"
16637
- ))));
16652
+ /* @__PURE__ */ React__default.createElement(AlertMessage, null)
16653
+ );
16638
16654
  }));
16639
16655
  }
16640
16656
  const Alert = ({
@@ -18359,7 +18375,16 @@ const FormBuilder = ({
18359
18375
  };
18360
18376
  const FormStatus = ({ pristine }) => {
18361
18377
  const pristineClass = pristine ? "text-green-500" : "text-red-500";
18362
- return /* @__PURE__ */ React.createElement(Circle$1, { className: cn("w-3 h-3 fill-current", pristineClass) });
18378
+ const label = pristine ? "No unsaved changes" : "Unsaved changes";
18379
+ return /* @__PURE__ */ React.createElement(
18380
+ Circle$1,
18381
+ {
18382
+ role: "img",
18383
+ "aria-label": label,
18384
+ className: cn("w-3 h-3 fill-current", pristineClass)
18385
+ },
18386
+ /* @__PURE__ */ React.createElement("title", null, label)
18387
+ );
18363
18388
  };
18364
18389
  const RelatedFilesBanner = () => {
18365
18390
  const cms = useCMS$1();
@@ -72511,9 +72536,9 @@ mutation addPendingDocumentMutation(
72511
72536
  throw new SessionExpiredError();
72512
72537
  }
72513
72538
  if (res.status !== 200) {
72514
- let errorMessage = `Unable to complete request, ${res.statusText}`;
72515
- const resBody = await res.json();
72516
- if (resBody.message) {
72539
+ let errorMessage = `Unable to complete request, ${res.statusText || res.status}`;
72540
+ const resBody = await res.json().catch(() => void 0);
72541
+ if (resBody == null ? void 0 : resBody.message) {
72517
72542
  errorMessage = `${errorMessage}, Response: ${resBody.message}`;
72518
72543
  }
72519
72544
  if (!this.isCustomContentApi) {
@@ -72597,7 +72622,7 @@ mutation addPendingDocumentMutation(
72597
72622
  }
72598
72623
  });
72599
72624
  if (!res.ok) {
72600
- let errorMessage = `There was an error creating a pull request. ${res.statusText}`;
72625
+ let errorMessage = `There was an error creating a pull request. ${res.statusText || res.status}`;
72601
72626
  if (res.status === 422) {
72602
72627
  errorMessage = `Please make sure you have made changes on ${branch} before creating a pull request.`;
72603
72628
  }
@@ -72780,8 +72805,10 @@ mutation addPendingDocumentMutation(
72780
72805
  });
72781
72806
  if (!res.ok) {
72782
72807
  console.error("There was an error creating a new branch.");
72783
- const error = await res.json();
72784
- throw new Error(error == null ? void 0 : error.message);
72808
+ const error = await res.json().catch(() => void 0);
72809
+ throw new Error(
72810
+ (error == null ? void 0 : error.message) ?? `Unable to create branch, ${res.statusText || res.status}`
72811
+ );
72785
72812
  }
72786
72813
  const values = await res.json();
72787
72814
  return parseRefForBranchName(values.data.ref);
@@ -72797,7 +72824,9 @@ mutation addPendingDocumentMutation(
72797
72824
  method: "GET"
72798
72825
  });
72799
72826
  if (!res.ok) {
72800
- throw new Error(`Failed to fetch latest version: ${res.statusText}`);
72827
+ throw new Error(
72828
+ `Failed to fetch latest version: ${res.statusText || res.status}`
72829
+ );
72801
72830
  }
72802
72831
  const data = await res.json();
72803
72832
  return data;
@@ -72846,7 +72875,7 @@ mutation addPendingDocumentMutation(
72846
72875
  }
72847
72876
  if (statusResponse.status !== 202) {
72848
72877
  const error = new Error(
72849
- statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText}`
72878
+ statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText || statusResponse.status}`
72850
72879
  );
72851
72880
  error.errorCode = "WORKFLOW_STATUS_FAILED";
72852
72881
  throw error;
@@ -74222,52 +74251,14 @@ const Layout = ({ children }) => {
74222
74251
  children
74223
74252
  ));
74224
74253
  };
74225
- const ErrorDialog = (props) => {
74226
- return /* @__PURE__ */ React__default.createElement(
74227
- "div",
74228
- {
74229
- style: {
74230
- background: "#efefef",
74231
- display: "flex",
74232
- alignItems: "center",
74233
- justifyContent: "center"
74234
- }
74235
- },
74236
- /* @__PURE__ */ React__default.createElement("style", null, " body { margin: 0; } "),
74237
- /* @__PURE__ */ React__default.createElement(
74238
- "div",
74239
- {
74240
- style: {
74241
- background: "#fff",
74242
- maxWidth: "400px",
74243
- padding: "20px",
74244
- fontFamily: "'Inter', sans-serif",
74245
- borderRadius: "5px",
74246
- boxShadow: "0 6px 24px rgb(0 37 91 / 5%), 0 2px 4px rgb(0 37 91 / 3%)"
74247
- }
74248
- },
74249
- /* @__PURE__ */ React__default.createElement("h3", { style: { color: "#eb6337" } }, props.title),
74250
- /* @__PURE__ */ React__default.createElement("p", null, props.message, ":"),
74251
- /* @__PURE__ */ React__default.createElement(
74252
- "pre",
74253
- {
74254
- style: { marginTop: "1rem", overflowX: "auto" }
74255
- },
74256
- `${props.error}`
74257
- ),
74258
- /* @__PURE__ */ React__default.createElement("p", null, "See our", " ", /* @__PURE__ */ React__default.createElement(
74259
- "a",
74260
- {
74261
- className: "text-gray-600",
74262
- style: { textDecoration: "underline" },
74263
- href: "https://tina.io/docs/r/FAQ/",
74264
- target: "_blank"
74265
- },
74266
- " ",
74267
- "Error FAQ",
74268
- " "
74269
- ), " ", "for more information.")
74270
- )
74254
+ const TROUBLESHOOTING_URL = "https://tina.io/docs/tinacloud/troubleshooting";
74255
+ const TroubleshootingLink = () => /* @__PURE__ */ React__default.createElement("a", { href: TROUBLESHOOTING_URL, target: "_blank", rel: "noopener noreferrer" }, "Read the TinaCloud troubleshooting guide");
74256
+ const ErrorDialog = (props) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, props.title && /* @__PURE__ */ React__default.createElement("h3", null, props.title), /* @__PURE__ */ React__default.createElement("p", null, props.message, ":"), /* @__PURE__ */ React__default.createElement("pre", { className: "overflow-x-auto" }, `${props.error}`), /* @__PURE__ */ React__default.createElement(TroubleshootingLink, null));
74257
+ const showErrorModal = (title, message, cms) => {
74258
+ if (cms.alerts.all.some((a) => a.level === "error")) return;
74259
+ cms.alerts.error(
74260
+ () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement(TroubleshootingLink, null)),
74261
+ { title }
74271
74262
  );
74272
74263
  };
74273
74264
  const LoadingPage = () => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
@@ -75499,18 +75490,24 @@ const shouldAutoOpenCollectionDocument = ({
75499
75490
  ((_b = (_a = collection.documents) == null ? void 0 : _a.edges) == null ? void 0 : _b.length) === 1 && // Check to make sure the file is not a folder
75500
75491
  ((_e = (_d = (_c = collection.documents) == null ? void 0 : _c.edges[0]) == null ? void 0 : _d.node) == null ? void 0 : _e.__typename) !== "Folder";
75501
75492
  };
75502
- const UnableToLoadModal = ({ message }) => /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, "Unable to load"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose" }, message)), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
75503
- Button$2,
75493
+ const UnableToLoadModal = ({ message }) => /* @__PURE__ */ React__default.createElement(
75494
+ ErrorModal,
75504
75495
  {
75505
- style: { flexGrow: 1 },
75506
- className: "w-full",
75507
- variant: "primary",
75508
- onClick: () => {
75509
- window.location.reload();
75510
- }
75496
+ title: "Unable to Load",
75497
+ actions: /* @__PURE__ */ React__default.createElement(
75498
+ Button$2,
75499
+ {
75500
+ className: "w-full sm:w-auto",
75501
+ variant: "primary",
75502
+ onClick: () => {
75503
+ window.location.reload();
75504
+ }
75505
+ },
75506
+ "Reload"
75507
+ )
75511
75508
  },
75512
- "Reload"
75513
- ))));
75509
+ message
75510
+ );
75514
75511
  const isValidSortKey = (sortKey, collection) => {
75515
75512
  if (collection.fields) {
75516
75513
  const sortKeys = collection.fields.map((x) => x.name);
@@ -75984,18 +75981,18 @@ const RenderForm$1 = ({
75984
75981
  }, 10);
75985
75982
  } catch (error) {
75986
75983
  if (isSessionExpiredError(error)) throw error;
75987
- const defaultErrorText = "There was a problem saving your document.";
75988
75984
  if (error.message && error.message.includes(ERR_ALREADY_EXISTS)) {
75989
75985
  cms.alerts.error(
75990
- `${defaultErrorText} The filename "${form.values.filename}.${collection.format || "md"}" is already used for another document, please modify it.`
75986
+ `The filename "${form.values.filename}.${collection.format || "md"}" is already used for another document, please modify it.`,
75987
+ { title: "Save Failed" }
75991
75988
  );
75992
75989
  } else {
75993
75990
  cms.alerts.error(
75994
75991
  () => ErrorDialog({
75995
- title: defaultErrorText,
75996
75992
  message: "Tina caught an error while creating the file",
75997
75993
  error
75998
- })
75994
+ }),
75995
+ { title: "Save Failed" }
75999
75996
  );
76000
75997
  }
76001
75998
  throw new Error(
@@ -76245,10 +76242,10 @@ const RenderForm = ({
76245
76242
  if (isSessionExpiredError(error)) throw error;
76246
76243
  cms.alerts.error(
76247
76244
  () => ErrorDialog({
76248
- title: "There was a problem saving your document",
76249
76245
  message: "Tina caught an error while updating the page",
76250
76246
  error
76251
- })
76247
+ }),
76248
+ { title: "Save Failed" }
76252
76249
  );
76253
76250
  console.error(error);
76254
76251
  throw new Error(
@@ -76337,15 +76334,6 @@ function resolvePreviewPath(splat, baseOrigin = typeof window !== "undefined" ?
76337
76334
  return { path: "/", offOrigin: true };
76338
76335
  }
76339
76336
  }
76340
- const TROUBLESHOOTING_URL = "https://tina.io/docs/tinacloud/troubleshooting";
76341
- const ErrorModalContent = (props) => {
76342
- const { title, message } = props;
76343
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", null, title), /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement("a", { href: TROUBLESHOOTING_URL, target: "_blank", rel: "noopener noreferrer" }, "Learn more"));
76344
- };
76345
- const showErrorModal = (title, message, cms) => {
76346
- if (cms.alerts.all.some((a) => a.level === "error")) return;
76347
- cms.alerts.error(() => /* @__PURE__ */ React__default.createElement(ErrorModalContent, { title, message }));
76348
- };
76349
76337
  const getBackendType = (client) => {
76350
76338
  var _a, _b, _c;
76351
76339
  if (!client) return "other";
@@ -76498,19 +76486,27 @@ const CheckSchema = ({
76498
76486
  });
76499
76487
  }
76500
76488
  }, [cms, JSON.stringify(schemaJson || {}), url]);
76501
- return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, schemaMissingError ? /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, "Branch Not Found"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose" }, "The current branch (", /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, currentBranch), ") has either been merged or deleted.")), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
76502
- Button$2,
76489
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, schemaMissingError ? /* @__PURE__ */ React__default.createElement(
76490
+ ErrorModal,
76503
76491
  {
76504
- style: { flexGrow: 1 },
76505
- className: "w-full",
76506
- variant: "primary",
76507
- onClick: () => {
76508
- window.localStorage.removeItem("tinacms-current-branch");
76509
- window.location.reload();
76510
- }
76492
+ title: "Branch Not Found",
76493
+ actions: /* @__PURE__ */ React__default.createElement(
76494
+ Button$2,
76495
+ {
76496
+ className: "w-full sm:w-auto",
76497
+ variant: "primary",
76498
+ onClick: () => {
76499
+ window.localStorage.removeItem("tinacms-current-branch");
76500
+ window.location.reload();
76501
+ }
76502
+ },
76503
+ "Switch back to default branch"
76504
+ )
76511
76505
  },
76512
- "Switch back to default branch"
76513
- )))) : children);
76506
+ "The current branch (",
76507
+ /* @__PURE__ */ React__default.createElement("span", { className: "font-bold" }, currentBranch),
76508
+ ") has either been merged or deleted."
76509
+ ) : children);
76514
76510
  };
76515
76511
  const TinaAdmin = ({
76516
76512
  preview,
@@ -76843,6 +76839,7 @@ export {
76843
76839
  EllipsisVerticalIcon,
76844
76840
  ErrorDialog,
76845
76841
  ErrorIcon,
76842
+ ErrorModal,
76846
76843
  EventBus,
76847
76844
  ExitIcon,
76848
76845
  FieldDescription,
@@ -77007,6 +77004,7 @@ export {
77007
77004
  safeAssertShape,
77008
77005
  sanitizeFilename,
77009
77006
  selectFieldClasses,
77007
+ showErrorModal,
77010
77008
  sortBranchListFn,
77011
77009
  staticRequest,
77012
77010
  tableHeadingStyle,
@@ -22,19 +22,23 @@ export declare class Alerts {
22
22
  * login modal. Alerts already showing are left alone.
23
23
  */
24
24
  private suppressed;
25
- add(level: AlertLevel, message: string | React.FunctionComponent, timeout?: number): () => void;
25
+ add(level: AlertLevel, message: string | React.FunctionComponent, timeout?: number, title?: string): () => void;
26
26
  dismiss(alert: Alert): void;
27
27
  subscribe(cb: Callback): () => void;
28
28
  get all(): Alert[];
29
29
  info(message: string | React.FunctionComponent, timeout?: number): () => void;
30
30
  success(message: string | React.FunctionComponent, timeout?: number): () => void;
31
31
  warn(message: string | React.FunctionComponent, timeout?: number): () => void;
32
- error(message: string | React.FunctionComponent, timeout?: number): () => void;
32
+ error(message: string | React.FunctionComponent, options?: number | ErrorAlertOptions): () => void;
33
33
  }
34
34
  export type AlertLevel = 'info' | 'success' | 'warn' | 'error';
35
+ export interface ErrorAlertOptions {
36
+ title?: string;
37
+ }
35
38
  export interface Alert {
36
39
  id: string;
37
40
  level: AlertLevel;
38
41
  message: string | React.FunctionComponent;
39
42
  timeout: number;
43
+ title?: string;
40
44
  }
@@ -45,7 +45,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
45
45
  children?: React.ReactNode;
46
46
  } & Omit<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
47
47
  asChild?: boolean;
48
- }, "ref">, "value" | "disabled" | "onSelect"> & {
48
+ }, "ref">, "value" | "onSelect" | "disabled"> & {
49
49
  disabled?: boolean;
50
50
  forceMount?: boolean;
51
51
  keywords?: string[];
@@ -102,7 +102,7 @@ export declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
102
102
  ref?: React.Ref<HTMLDivElement>;
103
103
  } & {
104
104
  asChild?: boolean;
105
- }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "disabled" | "onSelect"> & {
105
+ }, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "onSelect" | "disabled"> & {
106
106
  disabled?: boolean;
107
107
  onSelect?: (value: string) => void;
108
108
  value?: string;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export interface ErrorModalProps {
3
+ title: string;
4
+ actions: React.ReactNode;
5
+ close?: () => void;
6
+ children: React.ReactNode;
7
+ }
8
+ export declare const ErrorModal: ({ title, actions, close, children, }: ErrorModalProps) => React.JSX.Element;
@@ -2,3 +2,4 @@ export * from './modal-provider';
2
2
  export * from './modal';
3
3
  export * from './fullscreen-modal';
4
4
  export * from './popup-modal';
5
+ export * from './error-modal';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "tinacms",
3
3
  "type": "module",
4
4
  "typings": "dist/index.d.ts",
5
- "version": "3.14.2",
5
+ "version": "3.14.4",
6
6
  "main": "dist/index.js",
7
7
  "module": "./dist/index.js",
8
8
  "exports": {
@@ -110,10 +110,10 @@
110
110
  "webfontloader": "1.6.28",
111
111
  "yup": "^1.6.1",
112
112
  "zod": "^3.24.2",
113
- "@tinacms/schema-tools": "^2.10.1",
114
- "@tinacms/bridge": "^0.3.1",
115
113
  "@tinacms/mdx": "^2.3.0",
116
- "@tinacms/search": "^1.2.25"
114
+ "@tinacms/schema-tools": "^2.10.1",
115
+ "@tinacms/search": "^1.2.26",
116
+ "@tinacms/bridge": "^0.3.1"
117
117
  },
118
118
  "devDependencies": {
119
119
  "@graphql-tools/utils": "^10.8.1",