tinacms 3.7.1 → 3.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -34773,6 +34773,13 @@ const CollectionListPageSearchEvent = "collection-list-page-search";
34773
34773
  const CloudConfigNavComponentClickedEvent = "cloud-config-nav-component-clicked";
34774
34774
  const SlashCommandOpenedEvent = "slash-command-opened";
34775
34775
  const SlashCommandUsedEvent = "slash-command-used";
34776
+ const MediaUsageDashboardOpenedEvent = "media-dashboard-opened";
34777
+ const MediaUsageDashboardRefreshedEvent = "media-dashboard-refreshed";
34778
+ const MediaUsageDashboardTypeFilterEvent = "media-dashboard-type-filter-changed";
34779
+ const MediaUsageDashboardUsageFilterChangedEvent = "media-dashboard-usage-filter-changed";
34780
+ const MediaUsageDashboardRowExpandedEvent = "media-dashboard-row-expanded";
34781
+ const MediaUsageDashboardPreviewOpenedEvent = "media-dashboard-preview-opened";
34782
+ const MediaUsageDashboardDocumentLinkClickedEvent = "media-dashboard-document-link-clicked";
34776
34783
  let posthogClient = null;
34777
34784
  let isInitialized = false;
34778
34785
  let initializationPromise = null;
@@ -39564,12 +39571,6 @@ const ResetModal = ({ close: close2, reset: reset2 }) => {
39564
39571
  "Reset"
39565
39572
  ))));
39566
39573
  };
39567
- function AiFillWarning(props) {
39568
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 1024 1024" }, "child": [{ "tag": "path", "attr": { "d": "M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zM480 416c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v184c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V416zm32 352a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z" }, "child": [] }] })(props);
39569
- }
39570
- function AiOutlineLoading(props) {
39571
- return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 1024 1024" }, "child": [{ "tag": "path", "attr": { "d": "M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z" }, "child": [] }] })(props);
39572
- }
39573
39574
  const textFieldClasses = "shadow-inner focus:shadow-outline focus:border-blue-500 focus:outline-none block text-base placeholder:text-gray-300 px-3 py-2 text-gray-600 w-full bg-white border border-gray-200 transition-all ease-out duration-150 focus:text-gray-900 rounded";
39574
39575
  const disabledClasses$1 = "opacity-50 pointer-events-none cursor-not-allowed";
39575
39576
  const BaseTextField = React.forwardRef(({ className, disabled, ...rest }, ref) => {
@@ -41928,13 +41929,8 @@ const ImageField = wrapFieldsWithMeta(
41928
41929
  async function onChange(media) {
41929
41930
  var _a2, _b;
41930
41931
  if (media) {
41931
- const parsedValue = (
41932
- // @ts-ignore
41933
- typeof ((_b = (_a2 = cms == null ? void 0 : cms.media) == null ? void 0 : _a2.store) == null ? void 0 : _b.parse) === "function" ? (
41934
- // @ts-ignore
41935
- cms.media.store.parse(media)
41936
- ) : media
41937
- );
41932
+ const item = Array.isArray(media) ? media[0] : media;
41933
+ const parsedValue = typeof ((_b = (_a2 = cms == null ? void 0 : cms.media) == null ? void 0 : _a2.store) == null ? void 0 : _b.parse) === "function" ? cms.media.store.parse(item) : item.src || item;
41938
41934
  props.input.onChange(parsedValue);
41939
41935
  }
41940
41936
  }
@@ -43767,6 +43763,38 @@ const PasswordFieldPlugin = {
43767
43763
  },
43768
43764
  parse: parse$2
43769
43765
  };
43766
+ const DefaultDisplayOnlyField = () => {
43767
+ return /* @__PURE__ */ React.createElement("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3 text-sm text-gray-500 italic" }, "Display-only field — provide a component via ", /* @__PURE__ */ React.createElement("code", null, "ui.component"));
43768
+ };
43769
+ const DisplayOnlyFieldPlugin = {
43770
+ name: "displayOnly",
43771
+ Component: wrapFieldWithNoHeader(DefaultDisplayOnlyField)
43772
+ };
43773
+ const InfoBox = ({
43774
+ message,
43775
+ links
43776
+ }) => {
43777
+ const InfoBoxComponent = () => {
43778
+ return /* @__PURE__ */ React.createElement("div", { className: "relative w-full px-2 mb-5 last:mb-0" }, /* @__PURE__ */ React.createElement("div", { className: "rounded-lg border border-blue-200 bg-blue-50 p-3 text-sm w-full" }, /* @__PURE__ */ React.createElement("p", { className: "text-gray-700 whitespace-normal break-words" }, message), links && links.length > 0 && /* @__PURE__ */ React.createElement("ul", { className: "flex flex-col gap-1 mt-2" }, links.map((link) => /* @__PURE__ */ React.createElement("li", { key: link.url }, /* @__PURE__ */ React.createElement(
43779
+ "a",
43780
+ {
43781
+ href: link.url,
43782
+ target: "_blank",
43783
+ rel: "noopener noreferrer",
43784
+ className: "text-blue-600 underline hover:text-blue-800"
43785
+ },
43786
+ link.text
43787
+ ))))));
43788
+ };
43789
+ InfoBoxComponent.displayName = "InfoBox";
43790
+ return InfoBoxComponent;
43791
+ };
43792
+ function AiFillWarning(props) {
43793
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 1024 1024" }, "child": [{ "tag": "path", "attr": { "d": "M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zM480 416c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v184c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V416zm32 352a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z" }, "child": [] }] })(props);
43794
+ }
43795
+ function AiOutlineLoading(props) {
43796
+ return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 1024 1024" }, "child": [{ "tag": "path", "attr": { "d": "M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z" }, "child": [] }] })(props);
43797
+ }
43770
43798
  function GrCircleQuestion(props) {
43771
43799
  return GenIcon({ "tag": "svg", "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "strokeWidth": "2", "d": "M12,22 C17.5228475,22 22,17.5228475 22,12 C22,6.4771525 17.5228475,2 12,2 C6.4771525,2 2,6.4771525 2,12 C2,17.5228475 6.4771525,22 12,22 Z M12,15 L12,14 C12,13 12,12.5 13,12 C14,11.5 15,11 15,9.5 C15,8.5 14,7 12,7 C10,7 9,8.26413718 9,10 M12,16 L12,18" }, "child": [] }] })(props);
43772
43800
  }
@@ -44172,6 +44200,9 @@ function BranchSelectorTable({
44172
44200
  null
44173
44201
  );
44174
44202
  const cms = useCMS$1();
44203
+ const isCurrentBranchDeleted = !branchList.some(
44204
+ (b) => b.name === currentBranch
44205
+ );
44175
44206
  const columns = [
44176
44207
  {
44177
44208
  accessorKey: "name",
@@ -44348,7 +44379,7 @@ function BranchSelectorTable({
44348
44379
  {
44349
44380
  className: cn(
44350
44381
  "bg-transparent hover:!bg-transparent",
44351
- currentBranch === currentBranchData.name ? "border-l-[3px] border-l-tina-orange bg-[#f8fafc]" : ""
44382
+ isCurrentBranchDeleted ? "border-l-[3px] border-l-yellow-400 bg-yellow-50" : "border-l-[3px] border-l-tina-orange bg-[#f8fafc]"
44352
44383
  )
44353
44384
  },
44354
44385
  /* @__PURE__ */ React.createElement(TableCell, null, /* @__PURE__ */ React.createElement("div", { className: "flex flex-col gap-2" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, currentBranchData.protected ? /* @__PURE__ */ React.createElement(BiLockAlt, { className: "w-4 h-auto opacity-70 text-blue-500 flex-shrink-0" }) : /* @__PURE__ */ React.createElement(BiGitBranch, { className: "w-4 h-auto opacity-70 text-gray-600 flex-shrink-0" }), /* @__PURE__ */ React.createElement("p", { className: "font-bold" }, currentBranchData.name)), /* @__PURE__ */ React.createElement("div", { className: "w-fit mt-1" }, /* @__PURE__ */ React.createElement(
@@ -44360,6 +44391,15 @@ function BranchSelectorTable({
44360
44391
  },
44361
44392
  /* @__PURE__ */ React.createElement(BiPencil, { className: "w-3 h-auto inline-block mr-1" }),
44362
44393
  "Currently editing"
44394
+ )), isCurrentBranchDeleted && /* @__PURE__ */ React.createElement("div", { className: "w-fit" }, /* @__PURE__ */ React.createElement(
44395
+ Badge,
44396
+ {
44397
+ displayIcon: false,
44398
+ calloutStyle: "warning",
44399
+ className: "w-fit flex-shrink-0"
44400
+ },
44401
+ /* @__PURE__ */ React.createElement(AiFillWarning, { className: "w-3 h-auto inline-block mr-1" }),
44402
+ "Branch no longer exists"
44363
44403
  )))),
44364
44404
  /* @__PURE__ */ React.createElement(TableCell, null, ((_e = currentBranchData.indexStatus) == null ? void 0 : _e.timestamp) && /* @__PURE__ */ React.createElement("div", null, formatDistanceToNow(
44365
44405
  new Date(currentBranchData.indexStatus.timestamp)
@@ -46047,7 +46087,7 @@ function ListMediaItem({ item, onClick, active }) {
46047
46087
  return /* @__PURE__ */ React__default.createElement(
46048
46088
  "li",
46049
46089
  {
46050
- className: `group relative flex shrink-0 items-center transition duration-150 ease-out cursor-pointer border-b border-gray-150 ${active ? "bg-gradient-to-r from-white to-gray-50/50 text-blue-500 hover:bg-gray-50" : "bg-white hover:bg-gray-50/50 hover:text-blue-500"}`,
46090
+ className: `group relative flex shrink-0 items-center transition duration-150 ease-out cursor-pointer border-b border-gray-150 ${active ? "bg-gradient-to-r from-white to-gray-50/50 text-tina-orange hover:bg-gray-50" : "bg-white hover:bg-gray-50/50 hover:text-tina-orange"}`,
46051
46091
  onClick: () => {
46052
46092
  if (!active) {
46053
46093
  onClick(item);
@@ -46065,7 +46105,12 @@ function ListMediaItem({ item, onClick, active }) {
46065
46105
  src: thumbnail,
46066
46106
  alt: item.filename
46067
46107
  }
46068
- ) : /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-1/2 h-full fill-gray-300" })),
46108
+ ) : /* @__PURE__ */ React__default.createElement(
46109
+ FileIcon,
46110
+ {
46111
+ className: `w-1/2 h-full ${item.type === "dir" ? "fill-tina-orange" : "fill-gray-300"}`
46112
+ }
46113
+ )),
46069
46114
  /* @__PURE__ */ React__default.createElement(
46070
46115
  "span",
46071
46116
  {
@@ -46088,9 +46133,10 @@ function GridMediaItem({ item, active, onClick }) {
46088
46133
  "button",
46089
46134
  {
46090
46135
  className: cn(
46091
- "relative flex flex-col items-center justify-center w-full",
46136
+ "relative flex flex-col gap-1 items-center w-full outline-none rounded-lg overflow-hidden border-2 transition",
46092
46137
  {
46093
- "shadow hover:shadow-md hover:scale-103 hover:border-gray-150": !active,
46138
+ "border-black/10 hover:border-tina-orange/50 shadow-sm hover:shadow-md bg-white": !active,
46139
+ "border-tina-orange bg-tina-orange/10 shadow-md": active,
46094
46140
  "cursor-pointer": item.type === "dir"
46095
46141
  }
46096
46142
  ),
@@ -46102,30 +46148,23 @@ function GridMediaItem({ item, active, onClick }) {
46102
46148
  }
46103
46149
  }
46104
46150
  },
46105
- /* @__PURE__ */ React__default.createElement(
46106
- "span",
46107
- {
46108
- className: cn(
46109
- "absolute bottom-0 left-0 w-full text-xs text-white px-2 py-1 truncate z-10",
46110
- active ? "bg-blue-500/60" : "bg-black/60"
46111
- ),
46112
- style: { pointerEvents: "none" }
46113
- },
46114
- item.filename
46115
- ),
46116
46151
  item.new && /* @__PURE__ */ React__default.createElement("span", { className: "absolute top-1 right-1 rounded shadow bg-green-100 border border-green-200 text-[10px] tracking-wide font-bold text-green-600 px-1.5 py-0.5 z-10" }, "NEW"),
46117
- /* @__PURE__ */ React__default.createElement("div", { className: "relative w-full flex items-center justify-center" }, itemIsImage ? /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(
46152
+ /* @__PURE__ */ React__default.createElement("div", { className: "w-full overflow-hidden aspect-[1/1]" }, itemIsImage ? /* @__PURE__ */ React__default.createElement(
46118
46153
  "img",
46119
46154
  {
46120
- className: cn(
46121
- "block overflow-hidden object-center object-contain max-w-full max-h-[16rem] m-auto shadow",
46122
- { "border border-blue-500": active }
46123
- ),
46155
+ className: "block w-full h-full object-center object-cover",
46124
46156
  style: checkerboardStyle,
46125
46157
  src: thumbnail,
46126
46158
  alt: item.filename
46127
46159
  }
46128
- )) : /* @__PURE__ */ React__default.createElement("div", { className: "p-4 w-full flex flex-col gap-4 items-center justify-center" }, /* @__PURE__ */ React__default.createElement(FileIcon, { className: "w-[40%] h-auto fill-gray-300", size: 40 })))
46160
+ ) : /* @__PURE__ */ React__default.createElement("div", { className: "w-full h-full flex flex-col items-center justify-center" }, /* @__PURE__ */ React__default.createElement(
46161
+ FileIcon,
46162
+ {
46163
+ className: `w-[40%] h-auto ${item.type === "dir" ? "fill-tina-orange" : "fill-gray-300"}`,
46164
+ size: 40
46165
+ }
46166
+ ))),
46167
+ /* @__PURE__ */ React__default.createElement("div", { className: "mt-auto w-full px-2 py-1 text-sm truncate" }, item.filename)
46129
46168
  ));
46130
46169
  }
46131
46170
  const DeleteModal$1 = ({
@@ -46530,7 +46569,7 @@ function MediaPicker({
46530
46569
  className: "whitespace-nowrap"
46531
46570
  },
46532
46571
  "New Folder",
46533
- /* @__PURE__ */ React__default.createElement(BiFolder, { className: "w-6 h-full ml-2 opacity-70 text-blue-500" })
46572
+ /* @__PURE__ */ React__default.createElement(BiFolder, { className: "w-6 h-full ml-2 opacity-70 text-tina-orange" })
46534
46573
  ), /* @__PURE__ */ React__default.createElement(UploadButton, { onClick, uploading }))), /* @__PURE__ */ React__default.createElement("div", { className: "flex h-full overflow-hidden bg-white" }, /* @__PURE__ */ React__default.createElement("div", { className: "flex w-full flex-col h-full @container" }, /* @__PURE__ */ React__default.createElement(
46535
46574
  "ul",
46536
46575
  {
@@ -47207,6 +47246,9 @@ const MediaLightbox = ({
47207
47246
  const usageCount = item.usedIn.length;
47208
47247
  const mediaSrc = item.media.src;
47209
47248
  const directory = item.media.directory || "/";
47249
+ useEffect(() => {
47250
+ captureEvent(MediaUsageDashboardPreviewOpenedEvent);
47251
+ }, []);
47210
47252
  return /* @__PURE__ */ React__default.createElement(Dialog, { open: true, onOpenChange: (isOpen) => !isOpen && onClose() }, /* @__PURE__ */ React__default.createElement(DialogContent, { className: "w-auto max-w-[95vw] border border-gray-200 bg-white px-4 pt-12 pb-4 shadow-xl sm:max-w-fit" }, /* @__PURE__ */ React__default.createElement(DialogTitle, { className: "sr-only" }, "Preview: ", item.media.filename), /* @__PURE__ */ React__default.createElement(DialogDescription, { className: "sr-only" }, usageCount > 0 ? `Used in ${usageCount} ${usageCount === 1 ? "document" : "documents"}` : "Unused media file"), /* @__PURE__ */ React__default.createElement("div", { className: "mx-auto w-fit max-w-full rounded-lg border border-gray-200 bg-gray-50 p-2 sm:p-3" }, item.type === "video" ? /* @__PURE__ */ React__default.createElement(
47211
47253
  VideoLightboxContent,
47212
47254
  {
@@ -47537,7 +47579,13 @@ const MediaUsageTable = ({
47537
47579
  TableRow,
47538
47580
  {
47539
47581
  style: { contentVisibility: "auto" },
47540
- onClick: getUsageCount(row.original) > 0 ? row.getToggleExpandedHandler() : void 0,
47582
+ onClick: () => {
47583
+ getUsageCount(row.original) > 0;
47584
+ {
47585
+ row.toggleExpanded();
47586
+ captureEvent(MediaUsageDashboardRowExpandedEvent);
47587
+ }
47588
+ },
47541
47589
  className: getUsageCount(row.original) > 0 ? row.getIsExpanded() ? "cursor-pointer bg-[#FFF8F6] hover:bg-[#FFF8F6]" : "cursor-pointer" : ""
47542
47590
  },
47543
47591
  row.getVisibleCells().map((cell) => /* @__PURE__ */ React__default.createElement(
@@ -47578,7 +47626,12 @@ const MediaFilters = ({
47578
47626
  Select,
47579
47627
  {
47580
47628
  value: typeFilter,
47581
- onValueChange: (value) => setTypeFilter(value)
47629
+ onValueChange: (value) => {
47630
+ setTypeFilter(value);
47631
+ captureEvent(MediaUsageDashboardTypeFilterEvent, {
47632
+ type: value
47633
+ });
47634
+ }
47582
47635
  },
47583
47636
  /* @__PURE__ */ React__default.createElement(
47584
47637
  SelectTrigger,
@@ -47593,7 +47646,12 @@ const MediaFilters = ({
47593
47646
  Select,
47594
47647
  {
47595
47648
  value: usageFilter,
47596
- onValueChange: (value) => setUsageFilter(value)
47649
+ onValueChange: (value) => {
47650
+ setUsageFilter(value);
47651
+ captureEvent(MediaUsageDashboardUsageFilterChangedEvent, {
47652
+ usage: value
47653
+ });
47654
+ }
47597
47655
  },
47598
47656
  /* @__PURE__ */ React__default.createElement(
47599
47657
  SelectTrigger,
@@ -47625,7 +47683,10 @@ const ExpandedRowContent = ({
47625
47683
  "a",
47626
47684
  {
47627
47685
  href: `#/collections/${doc.collectionName}/~`,
47628
- onClick: () => onClose == null ? void 0 : onClose(),
47686
+ onClick: () => {
47687
+ onClose == null ? void 0 : onClose();
47688
+ captureEvent(MediaUsageDashboardDocumentLinkClickedEvent);
47689
+ },
47629
47690
  className: "underline hover:text-tina-orange-dark transition-colors"
47630
47691
  },
47631
47692
  doc.collectionLabel
@@ -47634,7 +47695,12 @@ const ExpandedRowContent = ({
47634
47695
  "a",
47635
47696
  {
47636
47697
  href: doc.editUrl,
47637
- onClick: () => onClose == null ? void 0 : onClose(),
47698
+ onClick: () => {
47699
+ onClose == null ? void 0 : onClose();
47700
+ captureEvent(
47701
+ MediaUsageDashboardDocumentLinkClickedEvent
47702
+ );
47703
+ },
47638
47704
  className: "underline hover:text-tina-orange-dark transition-colors break-all"
47639
47705
  },
47640
47706
  breadcrumb
@@ -47645,6 +47711,10 @@ const ExpandedRowContent = ({
47645
47711
  const MediaUsageDashboard = ({
47646
47712
  close: onClose
47647
47713
  }) => {
47714
+ useEffect(() => {
47715
+ console.log("MediaUsageDashboard");
47716
+ captureEvent(MediaUsageDashboardOpenedEvent);
47717
+ }, []);
47648
47718
  const { mediaItems, isLoading, errorOccurred, progress, refresh } = useMediaUsageScanner();
47649
47719
  const [lightboxImage, setLightboxImage] = useState(null);
47650
47720
  const stats = useMemo(() => {
@@ -47679,7 +47749,13 @@ const MediaUsageDashboard = ({
47679
47749
  Button,
47680
47750
  {
47681
47751
  variant: "outline",
47682
- onClick: refresh,
47752
+ onClick: async () => {
47753
+ await refresh();
47754
+ const payload = {
47755
+ errorOccured: errorOccurred
47756
+ };
47757
+ captureEvent(MediaUsageDashboardRefreshedEvent, payload);
47758
+ },
47683
47759
  disabled: isLoading,
47684
47760
  className: "flex items-center gap-2 shadow-sm font-medium transition-colors"
47685
47761
  },
@@ -47949,7 +48025,7 @@ const NavProvider = ({
47949
48025
  const name = "tinacms";
47950
48026
  const type = "module";
47951
48027
  const typings = "dist/index.d.ts";
47952
- const version$1 = "3.7.1";
48028
+ const version$1 = "3.7.3";
47953
48029
  const main = "dist/index.js";
47954
48030
  const module = "./dist/index.js";
47955
48031
  const exports = {
@@ -48911,7 +48987,7 @@ const TreeNodeComponent = ({
48911
48987
  node3.children.length > 0 && /* @__PURE__ */ React.createElement(
48912
48988
  BiChevronRight,
48913
48989
  {
48914
- className: `w-4 h-4 text-gray-500 transition-transform duration-150 -ml-1 ${isExpanded ? "rotate-90" : ""}`
48990
+ className: `w-4 h-4 flex-none text-gray-500 transition-transform duration-150 -ml-1 ${isExpanded ? "rotate-90" : ""}`
48915
48991
  }
48916
48992
  ),
48917
48993
  isExpanded ? /* @__PURE__ */ React.createElement(BiFolderOpen, { className: "w-4 h-4 text-orange-500 flex-none" }) : /* @__PURE__ */ React.createElement(BiFolder, { className: "w-4 h-4 text-orange-500 flex-none" }),
@@ -49002,16 +49078,21 @@ const FormLists = (props) => {
49002
49078
  onChange: (e3) => setShowReferences(e3.target.checked),
49003
49079
  className: "w-4 h-4 text-orange-500 border-gray-300 rounded focus:ring-orange-500"
49004
49080
  }
49005
- ), /* @__PURE__ */ React.createElement("span", null, "Show all references"))), /* @__PURE__ */ React.createElement("div", { className: "flex-1 overflow-x-auto overflow-y-auto min-h-0" }, cms.state.formLists.map((formList, index) => /* @__PURE__ */ React.createElement("div", { key: `${formList.id}-${index}` }, /* @__PURE__ */ React.createElement(
49081
+ ), /* @__PURE__ */ React.createElement("span", null, "Show all references"))), /* @__PURE__ */ React.createElement("div", { className: "flex-1 overflow-x-auto overflow-y-auto min-h-0 pb-16" }, /* @__PURE__ */ React.createElement(
49006
49082
  FormList,
49007
49083
  {
49008
49084
  setActiveFormId: (id2) => {
49009
49085
  cms.dispatch({ type: "forms:set-active-form-id", value: id2 });
49010
49086
  },
49011
- formList,
49087
+ formList: {
49088
+ id: "merged",
49089
+ label: "All",
49090
+ items: cms.state.formLists.flatMap((fl) => fl.items),
49091
+ formIds: cms.state.formLists.flatMap((fl) => fl.formIds)
49092
+ },
49012
49093
  showReferences
49013
49094
  }
49014
- )))));
49095
+ )));
49015
49096
  };
49016
49097
  const FormList = (props) => {
49017
49098
  const cms = useCMS();
@@ -49729,7 +49810,8 @@ const DEFAULT_FIELDS = [
49729
49810
  ReferenceFieldPlugin,
49730
49811
  ButtonToggleFieldPlugin,
49731
49812
  HiddenFieldPlugin,
49732
- PasswordFieldPlugin
49813
+ PasswordFieldPlugin,
49814
+ DisplayOnlyFieldPlugin
49733
49815
  ];
49734
49816
  class TinaCMS extends CMS {
49735
49817
  constructor({
@@ -65979,37 +66061,20 @@ const pathRelativeToCollection = (collectionPath, fullPath) => {
65979
66061
  `Path ${fullPath} not within collection path ${collectionPath}`
65980
66062
  );
65981
66063
  };
65982
- const formatDefaultBranchName = (filePath, crudType) => {
65983
- let result = filePath;
65984
- const contentPrefix = "content/";
65985
- if (result.startsWith(contentPrefix)) {
65986
- result = result.substring(contentPrefix.length);
65987
- }
65988
- const lastDot = result.lastIndexOf(".");
65989
- const lastSlash = Math.max(result.lastIndexOf("/"), result.lastIndexOf("\\"));
65990
- if (lastDot > lastSlash && lastDot > 0) {
65991
- result = result.slice(0, lastDot);
65992
- }
65993
- if (crudType === "delete") {
65994
- result = `❌-${result}`;
65995
- }
65996
- return result;
66064
+ const WORKFLOW_STEPS = [
66065
+ { id: 1, name: "Creating branch", description: "Setting up workspace" },
66066
+ { id: 2, name: "Updating branch", description: "Syncing content to branch" },
66067
+ { id: 3, name: "Creating pull request", description: "Preparing for review" }
66068
+ ];
66069
+ const formatTime = (seconds) => {
66070
+ const mins = Math.floor(seconds / 60);
66071
+ const secs = seconds % 60;
66072
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
65997
66073
  };
65998
- const CreateBranchModal = ({
65999
- close: close2,
66000
- safeSubmit,
66001
- path: path3,
66002
- values,
66003
- crudType,
66004
- tinaForm
66005
- }) => {
66074
+ function useEditorialWorkflow() {
66006
66075
  const cms = useCMS$1();
66007
66076
  const tinaApi = cms.api.tina;
66008
66077
  const { setCurrentBranch } = useBranchData();
66009
- const [disabled, setDisabled] = React.useState(false);
66010
- const [newBranchName, setNewBranchName] = React.useState(
66011
- formatDefaultBranchName(path3, crudType)
66012
- );
66013
66078
  const [isExecuting, setIsExecuting] = React.useState(false);
66014
66079
  const [errorMessage, setErrorMessage] = React.useState("");
66015
66080
  const [currentStep, setCurrentStep] = React.useState(0);
@@ -66028,33 +66093,21 @@ const CreateBranchModal = ({
66028
66093
  clearInterval(interval);
66029
66094
  };
66030
66095
  }, [isExecuting, currentStep]);
66031
- const formatTime = (seconds) => {
66032
- const mins = Math.floor(seconds / 60);
66033
- const secs = seconds % 60;
66034
- return `${mins}:${secs.toString().padStart(2, "0")}`;
66096
+ const reset2 = () => {
66097
+ setErrorMessage("");
66098
+ setIsExecuting(false);
66099
+ setCurrentStep(0);
66035
66100
  };
66036
- const steps = [
66037
- {
66038
- id: 1,
66039
- name: "Creating branch",
66040
- description: "Setting up workspace"
66041
- },
66042
- {
66043
- id: 2,
66044
- name: "Updating branch",
66045
- description: "Syncing content to branch"
66046
- },
66047
- {
66048
- id: 3,
66049
- name: "Creating pull request",
66050
- description: "Preparing for review"
66051
- }
66052
- ];
66053
- const executeEditorialWorkflow = async () => {
66101
+ const executeWorkflow = async ({
66102
+ branchName,
66103
+ baseBranch,
66104
+ path: path3,
66105
+ values,
66106
+ crudType,
66107
+ tinaForm
66108
+ }) => {
66054
66109
  var _a2;
66055
66110
  try {
66056
- const branchName = `tina/${newBranchName}`;
66057
- setDisabled(true);
66058
66111
  setIsExecuting(true);
66059
66112
  setCurrentStep(1);
66060
66113
  let graphql2 = "";
@@ -66084,7 +66137,7 @@ const CreateBranchModal = ({
66084
66137
  const relativePath = pathRelativeToCollection(collection.path, path3);
66085
66138
  const result = await tinaApi.executeEditorialWorkflow({
66086
66139
  branchName,
66087
- baseBranch: tinaApi.branch,
66140
+ baseBranch,
66088
66141
  prTitle: `${branchName.replace("tina/", "").replace("-", " ")} (PR from TinaCMS)`,
66089
66142
  graphQLContentOp: {
66090
66143
  query: graphql2,
@@ -66117,6 +66170,12 @@ const CreateBranchModal = ({
66117
66170
  throw new Error("Branch creation failed.");
66118
66171
  }
66119
66172
  setCurrentBranch(result.branchName);
66173
+ if (result.warning) {
66174
+ cms.alerts.warn(
66175
+ `${result.warning} Please reconnect GitHub authoring here: ${tinaApi.gitSettingsLink}`,
66176
+ 0
66177
+ );
66178
+ }
66120
66179
  cms.alerts.success(
66121
66180
  `Branch created successfully - Pull Request at ${result.pullRequestUrl}`,
66122
66181
  0
@@ -66125,115 +66184,209 @@ const CreateBranchModal = ({
66125
66184
  const folderPath = relativePath.includes("/") ? relativePath.substring(0, relativePath.lastIndexOf("/")) : "";
66126
66185
  window.location.hash = `#/collections/${collection.name}${folderPath ? `/${folderPath}` : ""}`;
66127
66186
  }
66128
- close2();
66187
+ return true;
66129
66188
  } catch (e3) {
66130
66189
  console.error(e3);
66131
- let errorMessage2 = "Branch operation failed, please try again. If the problem persists please contact support.";
66190
+ let errMessage = "Branch operation failed. Talking to GitHub was unsuccessful, please try again. If the problem persists please contact support at https://tina.io/support 🦙";
66132
66191
  const err = e3;
66133
66192
  if (err.errorCode) {
66134
66193
  switch (err.errorCode) {
66135
66194
  case EDITORIAL_WORKFLOW_ERROR.BRANCH_EXISTS:
66136
- errorMessage2 = "A branch with this name already exists";
66195
+ errMessage = "A branch with this name already exists";
66137
66196
  break;
66138
66197
  case EDITORIAL_WORKFLOW_ERROR.BRANCH_HIERARCHY_CONFLICT:
66139
- errorMessage2 = err.message || "Branch name conflicts with an existing branch";
66198
+ errMessage = err.message || "Branch name conflicts with an existing branch";
66140
66199
  break;
66141
66200
  case EDITORIAL_WORKFLOW_ERROR.VALIDATION_FAILED:
66142
- errorMessage2 = err.message || "Invalid branch name";
66201
+ errMessage = err.message || "Invalid branch name";
66202
+ break;
66203
+ default:
66204
+ errMessage = err.message || errMessage;
66143
66205
  break;
66144
66206
  }
66145
66207
  } else if (err.message) {
66146
66208
  if (err.message.toLowerCase().includes("already exists")) {
66147
- errorMessage2 = "A branch with this name already exists";
66209
+ errMessage = "A branch with this name already exists";
66148
66210
  } else if (err.message.toLowerCase().includes("conflict")) {
66149
- errorMessage2 = err.message;
66211
+ errMessage = err.message;
66150
66212
  }
66151
66213
  }
66152
- setErrorMessage(errorMessage2);
66153
- setDisabled(false);
66214
+ setErrorMessage(errMessage);
66154
66215
  setIsExecuting(false);
66155
66216
  setCurrentStep(0);
66217
+ return false;
66156
66218
  }
66157
66219
  };
66158
- const renderProgressIndicator = () => {
66159
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex justify-between my-8 relative px-5 sm:gap-x-8" }, /* @__PURE__ */ React.createElement(
66160
- "div",
66161
- {
66162
- className: "absolute top-5 h-0.5 bg-gray-200 -z-10",
66163
- style: { left: "50px", right: "50px" }
66220
+ return {
66221
+ isExecuting,
66222
+ errorMessage,
66223
+ currentStep,
66224
+ elapsedTime,
66225
+ executeWorkflow,
66226
+ reset: reset2
66227
+ };
66228
+ }
66229
+ const WorkflowProgressIndicator = ({
66230
+ currentStep,
66231
+ isExecuting,
66232
+ elapsedTime
66233
+ }) => {
66234
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex justify-between my-8 relative px-5 sm:gap-x-8" }, /* @__PURE__ */ React.createElement(
66235
+ "div",
66236
+ {
66237
+ className: "absolute top-5 h-0.5 bg-gray-200 -z-10",
66238
+ style: { left: "50px", right: "50px" }
66239
+ }
66240
+ ), currentStep > 1 && currentStep <= WORKFLOW_STEPS.length && /* @__PURE__ */ React.createElement(
66241
+ "div",
66242
+ {
66243
+ className: "absolute top-5 h-0.5 bg-tina-orange -z-10 transition-all duration-500",
66244
+ style: {
66245
+ left: "50px",
66246
+ width: `calc((100% - 100px) * ${(currentStep - 1) / (WORKFLOW_STEPS.length - 1)})`
66164
66247
  }
66165
- ), currentStep > 1 && currentStep <= steps.length && /* @__PURE__ */ React.createElement(
66166
- "div",
66167
- {
66168
- className: "absolute top-5 h-0.5 bg-tina-orange -z-10 transition-all duration-500",
66169
- style: {
66170
- left: "50px",
66171
- width: `calc((100% - 100px) * ${(currentStep - 1) / (steps.length - 1)})`
66172
- }
66248
+ }
66249
+ ), currentStep > 2 && /* @__PURE__ */ React.createElement(
66250
+ "div",
66251
+ {
66252
+ className: "absolute top-5 h-0.5 bg-green-500 -z-10 transition-all duration-500",
66253
+ style: {
66254
+ left: "50px",
66255
+ width: `calc((100% - 100px) * ${Math.min(1, (currentStep - 2) / (WORKFLOW_STEPS.length - 1))})`
66173
66256
  }
66174
- ), currentStep > 2 && /* @__PURE__ */ React.createElement(
66257
+ }
66258
+ ), WORKFLOW_STEPS.map((step, index) => {
66259
+ const stepNumber = index + 1;
66260
+ const isActive = stepNumber === currentStep;
66261
+ const isCompleted = stepNumber < currentStep;
66262
+ return /* @__PURE__ */ React.createElement("div", { key: step.id, className: "flex flex-col items-center relative" }, /* @__PURE__ */ React.createElement(
66175
66263
  "div",
66176
66264
  {
66177
- className: "absolute top-5 h-0.5 bg-green-500 -z-10 transition-all duration-500",
66178
- style: {
66179
- left: "50px",
66180
- width: `calc((100% - 100px) * ${Math.min(1, (currentStep - 2) / (steps.length - 1))})`
66181
- }
66182
- }
66183
- ), steps.map((step, index) => {
66184
- const stepNumber = index + 1;
66185
- const isActive = stepNumber === currentStep;
66186
- const isCompleted = stepNumber < currentStep;
66187
- return /* @__PURE__ */ React.createElement(
66188
- "div",
66265
+ className: `w-10 h-10 rounded-full flex items-center justify-center font-medium mb-3 border-2 transition-all duration-300 select-none ${isCompleted ? "bg-green-500 border-green-500 text-white" : isActive ? "bg-tina-orange border-tina-orange text-white" : "bg-white border-gray-200 text-gray-400"}`
66266
+ },
66267
+ isCompleted ? /* @__PURE__ */ React.createElement(
66268
+ "svg",
66189
66269
  {
66190
- key: step.id,
66191
- className: "flex flex-col items-center relative"
66270
+ className: "w-5 h-5",
66271
+ fill: "currentColor",
66272
+ viewBox: "0 0 20 20"
66192
66273
  },
66193
66274
  /* @__PURE__ */ React.createElement(
66194
- "div",
66275
+ "path",
66195
66276
  {
66196
- className: `w-10 h-10 rounded-full flex items-center justify-center font-medium mb-3 border-2 transition-all duration-300 select-none ${isCompleted ? "bg-green-500 border-green-500 text-white" : isActive ? "bg-tina-orange border-tina-orange text-white" : "bg-white border-gray-200 text-gray-400"}`
66197
- },
66198
- isCompleted ? /* @__PURE__ */ React.createElement(
66199
- "svg",
66200
- {
66201
- className: "w-5 h-5",
66202
- fill: "currentColor",
66203
- viewBox: "0 0 20 20"
66204
- },
66205
- /* @__PURE__ */ React.createElement(
66206
- "path",
66207
- {
66208
- fillRule: "evenodd",
66209
- d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
66210
- clipRule: "evenodd"
66211
- }
66212
- )
66213
- ) : isActive ? /* @__PURE__ */ React.createElement(AiOutlineLoading, { className: "animate-spin text-lg" }) : stepNumber
66214
- ),
66215
- /* @__PURE__ */ React.createElement("div", { className: "text-center max-w-24" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm font-semibold leading-tight" }, step.name), /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-400 mt-1 leading-tight" }, step.description))
66277
+ fillRule: "evenodd",
66278
+ d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z",
66279
+ clipRule: "evenodd"
66280
+ }
66281
+ )
66282
+ ) : isActive ? /* @__PURE__ */ React.createElement(AiOutlineLoading, { className: "animate-spin text-lg" }) : stepNumber
66283
+ ), /* @__PURE__ */ React.createElement("div", { className: "text-center max-w-24" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm font-semibold leading-tight" }, step.name), /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-400 mt-1 leading-tight" }, step.description)));
66284
+ })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500" }, "Estimated time: 1-2 min"), isExecuting && currentStep > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-sm text-gray-500 tabular-nums" }, /* @__PURE__ */ React.createElement("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20" }, /* @__PURE__ */ React.createElement(
66285
+ "path",
66286
+ {
66287
+ fillRule: "evenodd",
66288
+ d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z",
66289
+ clipRule: "evenodd"
66290
+ }
66291
+ )), formatTime(elapsedTime))), /* @__PURE__ */ React.createElement(
66292
+ "a",
66293
+ {
66294
+ className: "underline text-tina-orange-dark font-medium text-xs",
66295
+ href: "https://tina.io/docs/tinacloud/editorial-workflow",
66296
+ target: "_blank"
66297
+ },
66298
+ "Learn more about Editorial Workflow"
66299
+ ));
66300
+ };
66301
+ const formatDefaultBranchName = (filePath, crudType) => {
66302
+ let result = filePath;
66303
+ const contentPrefix = "content/";
66304
+ if (result.startsWith(contentPrefix)) {
66305
+ result = result.substring(contentPrefix.length);
66306
+ }
66307
+ const lastDot = result.lastIndexOf(".");
66308
+ const lastSlash = Math.max(result.lastIndexOf("/"), result.lastIndexOf("\\"));
66309
+ if (lastDot > lastSlash && lastDot > 0) {
66310
+ result = result.slice(0, lastDot);
66311
+ }
66312
+ if (crudType === "delete") {
66313
+ result = `❌-${result}`;
66314
+ }
66315
+ return result;
66316
+ };
66317
+ const CreateBranchModal = ({
66318
+ close: close2,
66319
+ safeSubmit,
66320
+ path: path3,
66321
+ values,
66322
+ crudType,
66323
+ tinaForm,
66324
+ onBaseBranchDeleted
66325
+ }) => {
66326
+ const cms = useCMS$1();
66327
+ const tinaApi = cms.api.tina;
66328
+ const [newBranchName, setNewBranchName] = React.useState(
66329
+ formatDefaultBranchName(path3, crudType)
66330
+ );
66331
+ const [isBranchGuardChecking, setIsBranchGuardChecking] = React.useState(false);
66332
+ const {
66333
+ isExecuting,
66334
+ errorMessage,
66335
+ currentStep,
66336
+ elapsedTime,
66337
+ executeWorkflow,
66338
+ reset: reset2
66339
+ } = useEditorialWorkflow();
66340
+ const executeEditorialWorkflow = async () => {
66341
+ setIsBranchGuardChecking(true);
66342
+ const baseBranch = decodeURIComponent(tinaApi.branch);
66343
+ let baseBranchExists = true;
66344
+ try {
66345
+ console.debug(
66346
+ "[tina:branch-guard] executeEditorialWorkflow: checking base branch:",
66347
+ baseBranch
66216
66348
  );
66217
- })), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "text-xs text-gray-500" }, "Estimated time: 1-2 min "), isExecuting && currentStep > 0 && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-sm text-gray-500 tabular-nums" }, /* @__PURE__ */ React.createElement("svg", { className: "w-4 h-4", fill: "currentColor", viewBox: "0 0 20 20" }, /* @__PURE__ */ React.createElement(
66218
- "path",
66219
- {
66220
- fillRule: "evenodd",
66221
- d: "M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z",
66222
- clipRule: "evenodd"
66223
- }
66224
- )), formatTime(elapsedTime))), /* @__PURE__ */ React.createElement(
66225
- "a",
66226
- {
66227
- className: "underline text-tina-orange-dark font-medium text-xs",
66228
- href: "https://tina.io/docs/tinacloud/editorial-workflow",
66229
- target: "_blank"
66230
- },
66231
- "Learn more about Editorial Workflow"
66232
- ));
66349
+ baseBranchExists = await tinaApi.branchExists(baseBranch);
66350
+ } catch (err) {
66351
+ console.error(
66352
+ "[tina:branch-guard] executeEditorialWorkflow: branchExists threw, failing open:",
66353
+ err
66354
+ );
66355
+ }
66356
+ console.debug(
66357
+ "[tina:branch-guard] executeEditorialWorkflow: base branch exists?",
66358
+ baseBranchExists
66359
+ );
66360
+ if (!baseBranchExists) {
66361
+ console.debug(
66362
+ "[tina:branch-guard] executeEditorialWorkflow: base branch deleted — handing off"
66363
+ );
66364
+ onBaseBranchDeleted == null ? void 0 : onBaseBranchDeleted();
66365
+ return;
66366
+ }
66367
+ setIsBranchGuardChecking(false);
66368
+ const success = await executeWorkflow({
66369
+ branchName: `tina/${newBranchName}`,
66370
+ baseBranch,
66371
+ path: path3,
66372
+ values,
66373
+ crudType,
66374
+ tinaForm
66375
+ });
66376
+ if (success) {
66377
+ close2();
66378
+ }
66233
66379
  };
66234
66380
  const renderStateContent = () => {
66235
66381
  if (isExecuting) {
66236
- return renderProgressIndicator();
66382
+ return /* @__PURE__ */ React.createElement(
66383
+ WorkflowProgressIndicator,
66384
+ {
66385
+ currentStep,
66386
+ isExecuting,
66387
+ elapsedTime
66388
+ }
66389
+ );
66237
66390
  } else {
66238
66391
  return /* @__PURE__ */ React.createElement("div", { className: "max-w-sm" }, errorMessage && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 mb-4 bg-red-50 border border-red-200 rounded" }, /* @__PURE__ */ React.createElement(BiError, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm" }, /* @__PURE__ */ React.createElement("b", null, "Error:"), " ", errorMessage)), /* @__PURE__ */ React.createElement("p", { className: "text-lg text-gray-700 font-bold mb-2" }, "First, let's create a copy"), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4 max-w-sm" }, "To make changes, you need to create a copy then get it approved and merged for it to go live.", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("span", { className: "text-gray-500" }, "Learn more about "), /* @__PURE__ */ React.createElement(
66239
66392
  "a",
@@ -66251,7 +66404,7 @@ const CreateBranchModal = ({
66251
66404
  placeholder: "e.g. {{PAGE-NAME}}-updates",
66252
66405
  value: newBranchName,
66253
66406
  onChange: (e3) => {
66254
- setErrorMessage("");
66407
+ reset2();
66255
66408
  setNewBranchName(e3.target.value);
66256
66409
  }
66257
66410
  }
@@ -66272,7 +66425,7 @@ const CreateBranchModal = ({
66272
66425
  variant: "primary",
66273
66426
  align: "start",
66274
66427
  className: "w-full sm:w-auto",
66275
- disabled: newBranchName === "" || disabled,
66428
+ disabled: newBranchName === "" || isBranchGuardChecking,
66276
66429
  onMainAction: executeEditorialWorkflow,
66277
66430
  items: [
66278
66431
  {
@@ -66310,6 +66463,89 @@ const PrefixedTextField = ({
66310
66463
  }
66311
66464
  )));
66312
66465
  };
66466
+ const BranchDeletedModal = ({
66467
+ branchName,
66468
+ close: close2,
66469
+ path: path3,
66470
+ values,
66471
+ crudType,
66472
+ tinaForm
66473
+ }) => {
66474
+ const cms = useCMS$1();
66475
+ const tinaApi = cms.api.tina;
66476
+ const [newBranchName, setNewBranchName] = React.useState("");
66477
+ const baseBranch = tinaApi.protectedBranches[0] || cms.api.tina.schema.config.config.repoProvider.defaultBranchName || "main";
66478
+ const {
66479
+ isExecuting,
66480
+ errorMessage,
66481
+ currentStep,
66482
+ elapsedTime,
66483
+ executeWorkflow,
66484
+ reset: reset2
66485
+ } = useEditorialWorkflow();
66486
+ const handleCreate = async () => {
66487
+ const success = await executeWorkflow({
66488
+ branchName: `tina/${newBranchName}`,
66489
+ baseBranch,
66490
+ path: path3,
66491
+ values,
66492
+ crudType,
66493
+ tinaForm
66494
+ });
66495
+ if (success)
66496
+ close2();
66497
+ };
66498
+ return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: isExecuting ? void 0 : close2 }, "Branch no longer exists"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, isExecuting ? /* @__PURE__ */ React.createElement(
66499
+ WorkflowProgressIndicator,
66500
+ {
66501
+ currentStep,
66502
+ isExecuting,
66503
+ elapsedTime
66504
+ }
66505
+ ) : /* @__PURE__ */ React.createElement("div", { className: "max-w-sm" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-start gap-3 p-3 mb-4 bg-yellow-50 border border-yellow-200 rounded text-yellow-800 text-sm" }, /* @__PURE__ */ React.createElement(
66506
+ GitBranchIcon,
66507
+ {
66508
+ className: "w-4 h-4 mt-0.5 flex-shrink-0 text-yellow-600",
66509
+ style: { fill: "none" }
66510
+ }
66511
+ ), /* @__PURE__ */ React.createElement("span", null, "The branch", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, branchName), " ", "no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.")), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 mb-4" }, "Create a new branch from", " ", /* @__PURE__ */ React.createElement("span", { className: "font-mono font-semibold" }, baseBranch), " to continue editing, or cancel and switch to an existing branch from the branch menu."), errorMessage && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 mb-4 bg-red-50 border border-red-200 rounded" }, /* @__PURE__ */ React.createElement(BiError, { className: "w-5 h-auto text-red-400 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm" }, /* @__PURE__ */ React.createElement("b", null, "Error:"), " ", errorMessage)), /* @__PURE__ */ React.createElement(
66512
+ PrefixedTextField,
66513
+ {
66514
+ name: "new-branch-name",
66515
+ label: "New Branch Name",
66516
+ placeholder: "e.g. my-updates",
66517
+ value: newBranchName,
66518
+ onChange: (e3) => {
66519
+ reset2();
66520
+ setNewBranchName(formatBranchName(e3.target.value));
66521
+ }
66522
+ }
66523
+ ))), !isExecuting && /* @__PURE__ */ React.createElement(ModalActions, { align: "end" }, /* @__PURE__ */ React.createElement(
66524
+ Button$2,
66525
+ {
66526
+ variant: "secondary",
66527
+ className: "w-full sm:w-auto",
66528
+ onClick: close2
66529
+ },
66530
+ "Cancel"
66531
+ ), /* @__PURE__ */ React.createElement(
66532
+ Button$2,
66533
+ {
66534
+ variant: "primary",
66535
+ className: "w-full sm:w-auto",
66536
+ disabled: !newBranchName,
66537
+ onClick: handleCreate
66538
+ },
66539
+ /* @__PURE__ */ React.createElement(
66540
+ GitBranchIcon,
66541
+ {
66542
+ className: "w-4 h-4 mr-1",
66543
+ style: { fill: "none" }
66544
+ }
66545
+ ),
66546
+ "Create new branch"
66547
+ ))));
66548
+ };
66313
66549
  const NoFieldsPlaceholder = () => /* @__PURE__ */ React.createElement(
66314
66550
  "div",
66315
66551
  {
@@ -66366,6 +66602,8 @@ const FormBuilder = ({
66366
66602
  const cms = useCMS$1();
66367
66603
  const hideFooter = !!rest.hideFooter;
66368
66604
  const [createBranchModalOpen, setCreateBranchModalOpen] = React.useState(false);
66605
+ const [deletedBranchModalOpen, setDeletedBranchModalOpen] = React.useState(false);
66606
+ const [isGuardChecking, setIsGuardChecking] = React.useState(false);
66369
66607
  const tinaForm = form.tinaForm;
66370
66608
  const finalForm = form.tinaForm.finalForm;
66371
66609
  React.useEffect(() => {
@@ -66425,26 +66663,79 @@ const FormBuilder = ({
66425
66663
  const canSubmit = !pristine && !submitting && !hasValidationErrors && !(invalid && !dirtySinceLastSubmit);
66426
66664
  const safeSubmit = async () => {
66427
66665
  if (canSubmit) {
66666
+ const alertsBefore = new Set(cms.alerts.all.map((a2) => a2.id));
66667
+ console.debug(
66668
+ "[tina:branch-guard] safeSubmit: calling handleSubmit"
66669
+ );
66428
66670
  const result = await handleSubmit();
66429
66671
  if (result && result[FORM_ERROR]) {
66430
66672
  const error2 = result[FORM_ERROR];
66673
+ const errorMsg = error2 instanceof Error ? error2.message : String(error2);
66674
+ console.debug(
66675
+ "[tina:branch-guard] safeSubmit: FORM_ERROR detected:",
66676
+ errorMsg
66677
+ );
66678
+ if (/branch.*not found/i.test(errorMsg)) {
66679
+ console.debug(
66680
+ "[tina:branch-guard] safeSubmit: branch-not-found — dismissing alert and opening modal"
66681
+ );
66682
+ for (const alert of cms.alerts.all) {
66683
+ if (!alertsBefore.has(alert.id) && alert.level === "error") {
66684
+ cms.alerts.dismiss(alert);
66685
+ }
66686
+ }
66687
+ setDeletedBranchModalOpen(true);
66688
+ return;
66689
+ }
66431
66690
  captureEvent(SaveContentErrorEvent, {
66432
66691
  documentPath: tinaForm.path,
66433
- error: error2 instanceof Error ? error2.message : String(error2)
66692
+ error: errorMsg
66434
66693
  });
66435
66694
  } else {
66436
66695
  captureEvent(SavedContentEvent, {
66437
66696
  documentPath: tinaForm.path
66438
66697
  });
66439
66698
  }
66699
+ } else {
66700
+ console.debug(
66701
+ "[tina:branch-guard] safeSubmit: skipped — canSubmit is false"
66702
+ );
66440
66703
  }
66441
66704
  };
66442
66705
  const safeHandleSubmit = async () => {
66706
+ setIsGuardChecking(true);
66707
+ const currentBranch = decodeURIComponent(cms.api.tina.getBranch());
66708
+ let exists = true;
66709
+ try {
66710
+ console.debug(
66711
+ "[tina:branch-guard] safeHandleSubmit: checking branch:",
66712
+ currentBranch
66713
+ );
66714
+ exists = await cms.api.tina.branchExists(currentBranch);
66715
+ } catch (err) {
66716
+ console.error(
66717
+ "[tina:branch-guard] safeHandleSubmit: branchExists threw, failing open:",
66718
+ err
66719
+ );
66720
+ }
66721
+ console.debug(
66722
+ "[tina:branch-guard] safeHandleSubmit: branchExists returned:",
66723
+ exists
66724
+ );
66725
+ if (!exists) {
66726
+ console.debug(
66727
+ "[tina:branch-guard] safeHandleSubmit: branch missing — opening modal"
66728
+ );
66729
+ setIsGuardChecking(false);
66730
+ setDeletedBranchModalOpen(true);
66731
+ return;
66732
+ }
66443
66733
  if (usingProtectedBranch) {
66444
66734
  setCreateBranchModalOpen(true);
66445
66735
  } else {
66446
- safeSubmit();
66736
+ await safeSubmit();
66447
66737
  }
66738
+ setIsGuardChecking(false);
66448
66739
  };
66449
66740
  return /* @__PURE__ */ React.createElement(React.Fragment, null, createBranchModalOpen && /* @__PURE__ */ React.createElement(
66450
66741
  CreateBranchModal,
@@ -66454,7 +66745,21 @@ const FormBuilder = ({
66454
66745
  path: tinaForm.path,
66455
66746
  values: tinaForm.values,
66456
66747
  tinaForm,
66457
- close: () => setCreateBranchModalOpen(false)
66748
+ close: () => setCreateBranchModalOpen(false),
66749
+ onBaseBranchDeleted: () => {
66750
+ setCreateBranchModalOpen(false);
66751
+ setDeletedBranchModalOpen(true);
66752
+ }
66753
+ }
66754
+ ), deletedBranchModalOpen && /* @__PURE__ */ React.createElement(
66755
+ BranchDeletedModal,
66756
+ {
66757
+ branchName: decodeURIComponent(cms.api.tina.getBranch()),
66758
+ close: () => setDeletedBranchModalOpen(false),
66759
+ path: tinaForm.path,
66760
+ values: tinaForm.values,
66761
+ crudType: tinaForm.crudType,
66762
+ tinaForm
66458
66763
  }
66459
66764
  ), /* @__PURE__ */ React.createElement(DragDropContext, { onDragEnd: moveArrayItem }, /* @__PURE__ */ React.createElement(FormKeyBindings, { onSubmit: safeHandleSubmit }), /* @__PURE__ */ React.createElement(FormPortalProvider, null, /* @__PURE__ */ React.createElement(FormWrapper, { id: tinaForm.id }, (tinaForm == null ? void 0 : tinaForm.fields.length) ? /* @__PURE__ */ React.createElement(
66460
66765
  FieldsBuilder,
@@ -66478,8 +66783,8 @@ const FormBuilder = ({
66478
66783
  Button$2,
66479
66784
  {
66480
66785
  onClick: safeHandleSubmit,
66481
- disabled: !canSubmit,
66482
- busy: submitting,
66786
+ disabled: !canSubmit || isGuardChecking,
66787
+ busy: submitting || isGuardChecking,
66483
66788
  variant: "primary"
66484
66789
  },
66485
66790
  submitting && /* @__PURE__ */ React.createElement(LoadingDots, null),
@@ -68119,7 +68424,9 @@ const useImageToolbarButton = (state) => {
68119
68424
  allowDelete: true,
68120
68425
  directory: "",
68121
68426
  onSelect: (media) => {
68122
- insertImg(editor, media);
68427
+ var _a2, _b;
68428
+ const src = typeof ((_b = (_a2 = cms == null ? void 0 : cms.media) == null ? void 0 : _a2.store) == null ? void 0 : _b.parse) === "function" ? cms.media.store.parse(media) : media.src;
68429
+ insertImg(editor, { ...media, src: src || media.src });
68123
68430
  }
68124
68431
  });
68125
68432
  };
@@ -121593,6 +121900,9 @@ mutation addPendingDocumentMutation(
121593
121900
  get appDashboardLink() {
121594
121901
  return `${this.frontendUrl}/projects/${this.clientId}`;
121595
121902
  }
121903
+ get gitSettingsLink() {
121904
+ return `${this.frontendUrl}/account/git`;
121905
+ }
121596
121906
  async checkSyncStatus({
121597
121907
  assetsSyncing
121598
121908
  }) {
@@ -121780,6 +122090,12 @@ mutation addPendingDocumentMutation(
121780
122090
  var _a2;
121781
122091
  return this.usingEditorialWorkflow && ((_a2 = this.protectedBranches) == null ? void 0 : _a2.includes(decodeURIComponent(this.branch)));
121782
122092
  }
122093
+ async branchExists(branchName) {
122094
+ if (this.isLocalMode)
122095
+ return true;
122096
+ const branches = await this.listBranches({ includeIndexStatus: false });
122097
+ return branches.some((b) => b.name === branchName);
122098
+ }
121783
122099
  async createBranch({ baseBranch, branchName }) {
121784
122100
  const url = `${this.contentApiBase}/github/${this.clientId}/create_branch`;
121785
122101
  try {
@@ -121872,29 +122188,50 @@ mutation addPendingDocumentMutation(
121872
122188
  while (attempts < maxAttempts) {
121873
122189
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
121874
122190
  attempts++;
121875
- const statusUrl = `${this.contentApiBase}/editorial-workflow/${this.clientId}/status/${requestId}`;
121876
- const statusResponse = await this.authProvider.fetchWithToken(statusUrl);
121877
- if (!statusResponse.ok) {
121878
- throw new Error(
121879
- `Failed to check workflow status: ${statusResponse.statusText}`
121880
- );
121881
- }
121882
- const statusResponseBody = await statusResponse.json();
121883
- if (options.onStatusUpdate) {
121884
- options.onStatusUpdate({
121885
- status: statusResponseBody.status,
121886
- message: statusResponseBody.message || `Status: ${statusResponseBody.status}`
121887
- });
121888
- }
121889
- if (statusResponse.status === 200) {
121890
- return {
121891
- branchName: statusResponseBody.branchName,
121892
- pullRequestUrl: statusResponseBody.pullRequestUrl
121893
- };
121894
- }
121895
- if (!statusResponse.ok) {
121896
- throw new Error(
121897
- statusResponseBody.message || "Editorial workflow failed"
122191
+ try {
122192
+ const statusUrl = `${this.contentApiBase}/editorial-workflow/${this.clientId}/status/${requestId}`;
122193
+ const statusResponse = await this.authProvider.fetchWithToken(statusUrl);
122194
+ const statusResponseBody = await statusResponse.json();
122195
+ if (options.onStatusUpdate) {
122196
+ options.onStatusUpdate({
122197
+ status: statusResponseBody.status,
122198
+ message: statusResponseBody.message || `Status: ${statusResponseBody.status}`
122199
+ });
122200
+ }
122201
+ if (statusResponseBody.status === EDITORIAL_WORKFLOW_STATUS.ERROR || statusResponse.status === 500) {
122202
+ if (statusResponseBody.pullRequestUrl) {
122203
+ return {
122204
+ branchName: statusResponseBody.branchName,
122205
+ pullRequestUrl: statusResponseBody.pullRequestUrl,
122206
+ warning: statusResponseBody.message
122207
+ };
122208
+ }
122209
+ const error2 = new Error(
122210
+ statusResponseBody.message || "Editorial workflow failed"
122211
+ );
122212
+ error2.errorCode = statusResponseBody.errorCode || "WORKFLOW_FAILED";
122213
+ throw error2;
122214
+ }
122215
+ if (statusResponse.status === 200) {
122216
+ return {
122217
+ branchName: statusResponseBody.branchName,
122218
+ pullRequestUrl: statusResponseBody.pullRequestUrl
122219
+ };
122220
+ }
122221
+ if (statusResponse.status !== 202) {
122222
+ const error2 = new Error(
122223
+ statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText}`
122224
+ );
122225
+ error2.errorCode = "WORKFLOW_STATUS_FAILED";
122226
+ throw error2;
122227
+ }
122228
+ } catch (error2) {
122229
+ if (error2.errorCode) {
122230
+ throw error2;
122231
+ }
122232
+ console.warn(
122233
+ `Editorial workflow status poll failed (attempt ${attempts}/${maxAttempts}), retrying...`,
122234
+ error2
121898
122235
  );
121899
122236
  }
121900
122237
  }
@@ -122121,7 +122458,7 @@ const AuthWallInner = ({
122121
122458
  const loginScreen = client.authProvider.getLoginScreen();
122122
122459
  if (loginStrategy === "LoginScreen" && !loginScreen) {
122123
122460
  throw new Error(
122124
- "LoginScreen is set as the login strategy but no login screen component was provided"
122461
+ "LoginScreen is set as the login strategy but no login screen component was provided."
122125
122462
  );
122126
122463
  }
122127
122464
  const [activeModal, setActiveModal] = useState(null);
@@ -122148,7 +122485,7 @@ const AuthWallInner = ({
122148
122485
  } else {
122149
122486
  setErrorMessage({
122150
122487
  title: "Access Denied:",
122151
- message: "Not Authorized To Edit"
122488
+ message: "Not authorized to edit."
122152
122489
  });
122153
122490
  setActiveModal("error");
122154
122491
  }
@@ -122207,16 +122544,16 @@ const AuthWallInner = ({
122207
122544
  });
122208
122545
  }
122209
122546
  };
122210
- let modalTitle = "Let’s get you editing with TinaCMS...";
122547
+ let modalTitle = "Let’s get you editing with TinaCMS!";
122211
122548
  if (activeModal === "authenticate" && loginStrategy === "Redirect" && !isTinaCloud) {
122212
122549
  modalTitle = "Enter into edit mode";
122213
122550
  } else if (activeModal === "authenticate" && loginStrategy === "UsernamePassword") {
122214
- modalTitle = "Let’s get you editing with TinaCMS...";
122551
+ modalTitle = "Let’s get you editing with TinaCMS!";
122215
122552
  } else if (activeModal === "error") {
122216
122553
  if (loginStrategy === "Redirect" && !isTinaCloud) {
122217
122554
  modalTitle = "Enter into edit mode";
122218
122555
  } else if (loginStrategy === "UsernamePassword") {
122219
- modalTitle = "Let’s get you editing with TinaCMS...";
122556
+ modalTitle = "Let’s get you editing with TinaCMS!";
122220
122557
  }
122221
122558
  }
122222
122559
  return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, activeModal === "authenticate" && loginStrategy === "Redirect" && /* @__PURE__ */ React__default.createElement(
@@ -122230,7 +122567,7 @@ const AuthWallInner = ({
122230
122567
  alt: "Tina the Llama playing a large orange key like a guitar.",
122231
122568
  width: 816,
122232
122569
  height: 816,
122233
- style: { maxWidth: "100%", margin: "0 auto", display: "block" }
122570
+ style: { width: "16rem", margin: "0 auto", display: "block" }
122234
122571
  }
122235
122572
  ) : "When you save, changes will be saved to the local filesystem.",
122236
122573
  close,
@@ -124666,7 +125003,7 @@ const RenderForm$1 = ({
124666
125003
  }
124667
125004
  return true;
124668
125005
  }
124669
- const isValid = /[\.\-_\/a-zA-Z0-9]*$/.test(value);
125006
+ const isValid = /^[\.\-_\/a-zA-Z0-9]*$/.test(value);
124670
125007
  if (value && !isValid) {
124671
125008
  return "Must contain only a-z, A-Z, 0-9, -, _, ., or /.";
124672
125009
  }
@@ -125516,6 +125853,7 @@ export {
125516
125853
  DateFieldPlugin,
125517
125854
  DeleteImageButton,
125518
125855
  Dismissible,
125856
+ DisplayOnlyFieldPlugin,
125519
125857
  DragHandle,
125520
125858
  DragIcon,
125521
125859
  DropdownButton,
@@ -125563,6 +125901,7 @@ export {
125563
125901
  ImageField,
125564
125902
  ImageFieldPlugin,
125565
125903
  ImageUpload,
125904
+ InfoBox,
125566
125905
  InfoIcon,
125567
125906
  Input$1 as Input,
125568
125907
  ItalicIcon$1 as ItalicIcon,