tinacms 3.8.3 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +0 -4
- package/dist/index.js +1156 -567
- package/dist/internalClient/index.d.ts +30 -8
- package/dist/toolkit/components/media/index.d.ts +1 -1
- package/dist/toolkit/components/media/media-workflow-overlay.d.ts +2 -0
- package/dist/toolkit/components/media/utils.d.ts +8 -0
- package/dist/toolkit/core/event.d.ts +15 -1
- package/dist/toolkit/core/media-store.default.d.ts +31 -4
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/command.d.ts +8 -8
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/heading-items.d.ts +15 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/components/plate-ui/input.d.ts +1 -1
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/core/autoformat/autoformat-block.d.ts +2 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/editor-plugins.d.ts +171 -165
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/toolbar/toolbar-overrides.d.ts +3 -2
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/toolbar/toolbar-provider.d.ts +10 -1
- package/dist/toolkit/form-builder/create-branch-modal.d.ts +9 -0
- package/dist/toolkit/form-builder/editorial-workflow-progress-modal.d.ts +15 -0
- package/dist/toolkit/form-builder/editorial-workflow-utils.d.ts +20 -0
- package/dist/toolkit/form-builder/use-editorial-workflow.d.ts +2 -0
- package/dist/toolkit/git-client/git-client.d.ts +0 -6
- package/dist/toolkit/git-client/git-file.d.ts +1 -1
- package/dist/toolkit/index.d.ts +2 -1
- package/dist/toolkit/plugin-branch-switcher/branch-switcher.d.ts +2 -1
- package/dist/toolkit/plugin-branch-switcher/format-branch-name.d.ts +8 -0
- package/dist/toolkit/react-core/use-cms-event.d.ts +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -36,6 +36,8 @@ import { useHTMLInputCursorState, useComboboxInput } from "@udecode/plate-combob
|
|
|
36
36
|
import { useComboboxContext, Combobox as Combobox$1, useComboboxStore, ComboboxProvider, Portal, ComboboxPopover, ComboboxItem } from "@ariakit/react";
|
|
37
37
|
import { filterWords } from "@udecode/plate-combobox";
|
|
38
38
|
import { toggleList, unwrapList, getListItemEntry } from "@udecode/plate-list";
|
|
39
|
+
import { normalizeHeadingLevels, ALL_HEADING_LEVELS, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, resolveForm, normalizePath, canonicalPath, validateSchema } from "@tinacms/schema-tools";
|
|
40
|
+
import { NAMER, resolveField } from "@tinacms/schema-tools";
|
|
39
41
|
import { useBlockSelected, BlockSelectionPlugin } from "@udecode/plate-selection/react";
|
|
40
42
|
import "@udecode/plate-dnd";
|
|
41
43
|
import { setCellBackground } from "@udecode/plate-table";
|
|
@@ -56,10 +58,10 @@ import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, close
|
|
|
56
58
|
import { sortableKeyboardCoordinates, useSortable, SortableContext, verticalListSortingStrategy, defaultAnimateLayoutChanges } from "@dnd-kit/sortable";
|
|
57
59
|
import { CSS } from "@dnd-kit/utilities";
|
|
58
60
|
import { FaSpinner, FaCircle, FaFolder, FaFile, FaLock, FaUnlock } from "react-icons/fa";
|
|
61
|
+
import { AiFillWarning, AiOutlineLoading } from "react-icons/ai";
|
|
59
62
|
import { buildSchema, print, getIntrospectionQuery, buildClientSchema, parse as parse$3 } from "graphql";
|
|
60
63
|
import { diff as diff$1 } from "@graphql-inspector/core";
|
|
61
64
|
import { processDocumentForIndexing, queryToSearchIndexQuery, optionsToSearchIndexOptions, parseSearchIndexResponse } from "@tinacms/search/index-client";
|
|
62
|
-
import { AiFillWarning, AiOutlineLoading } from "react-icons/ai";
|
|
63
65
|
import { HexColorPicker } from "react-colorful";
|
|
64
66
|
import { MdKeyboardArrowDown, MdOutlineClear, MdArrowForward, MdAccessTime, MdOutlineDataSaverOff, MdCheckCircle, MdWifiOff, MdOutlineSettings, MdOutlinePhotoLibrary, MdVpnKey, MdImage, MdOutlineCloud, MdWarning, MdInfo, MdError, MdSyncProblem, MdOutlinePerson, MdOutlineHelpOutline } from "react-icons/md";
|
|
65
67
|
import * as dropzone from "react-dropzone";
|
|
@@ -93,8 +95,6 @@ import { VscNewFile } from "react-icons/vsc";
|
|
|
93
95
|
import { TbLogs } from "react-icons/tb";
|
|
94
96
|
import { ImUsers, ImFilesEmpty } from "react-icons/im";
|
|
95
97
|
import { PiSidebarSimpleLight } from "react-icons/pi";
|
|
96
|
-
import { TinaSchema, addNamespaceToSchema, parseURL, resolveForm, normalizePath, canonicalPath, validateSchema } from "@tinacms/schema-tools";
|
|
97
|
-
import { NAMER, resolveField } from "@tinacms/schema-tools";
|
|
98
98
|
import gql from "graphql-tag";
|
|
99
99
|
import { useLocation, NavLink, useNavigate, useParams, Link as Link$1, HashRouter, Routes, Route } from "react-router-dom";
|
|
100
100
|
import { RiHome2Line } from "react-icons/ri";
|
|
@@ -1356,7 +1356,7 @@ function CodeBlockCombobox({
|
|
|
1356
1356
|
const element = useElement();
|
|
1357
1357
|
const value = element.lang || "plaintext";
|
|
1358
1358
|
const [searchValue, setSearchValue] = React__default.useState("");
|
|
1359
|
-
const
|
|
1359
|
+
const items = React__default.useMemo(
|
|
1360
1360
|
() => languages.filter(
|
|
1361
1361
|
(language) => !searchValue || language.label.toLowerCase().includes(searchValue.toLowerCase())
|
|
1362
1362
|
),
|
|
@@ -1394,7 +1394,7 @@ function CodeBlockCombobox({
|
|
|
1394
1394
|
onValueChange: (value2) => setSearchValue(value2),
|
|
1395
1395
|
placeholder: "Search language..."
|
|
1396
1396
|
}
|
|
1397
|
-
), /* @__PURE__ */ React__default.createElement(CommandEmpty$1, null, "No language found."), /* @__PURE__ */ React__default.createElement(CommandList$1, { className: "h-48 overflow-y-auto" }, /* @__PURE__ */ React__default.createElement(CommandGroup$1, null,
|
|
1397
|
+
), /* @__PURE__ */ React__default.createElement(CommandEmpty$1, null, "No language found."), /* @__PURE__ */ React__default.createElement(CommandList$1, { className: "h-48 overflow-y-auto" }, /* @__PURE__ */ React__default.createElement(CommandGroup$1, null, items.map((language) => /* @__PURE__ */ React__default.createElement(
|
|
1398
1398
|
CommandItem$1,
|
|
1399
1399
|
{
|
|
1400
1400
|
key: language.label,
|
|
@@ -2435,16 +2435,16 @@ const InlineCombobox = ({
|
|
|
2435
2435
|
const store = useComboboxStore({
|
|
2436
2436
|
setValue: (newValue) => startTransition(() => setValue(newValue))
|
|
2437
2437
|
});
|
|
2438
|
-
const
|
|
2438
|
+
const items = store.useState("items");
|
|
2439
2439
|
useEffect(() => {
|
|
2440
2440
|
if (!store.getState().activeId) {
|
|
2441
2441
|
store.setActiveId(store.first());
|
|
2442
2442
|
}
|
|
2443
|
-
}, [
|
|
2443
|
+
}, [items, store]);
|
|
2444
2444
|
return /* @__PURE__ */ React__default.createElement("span", { contentEditable: false }, /* @__PURE__ */ React__default.createElement(
|
|
2445
2445
|
ComboboxProvider,
|
|
2446
2446
|
{
|
|
2447
|
-
open: (
|
|
2447
|
+
open: (items.length > 0 || hasEmpty) && (!hideWhenNoValue || value.length > 0),
|
|
2448
2448
|
store
|
|
2449
2449
|
},
|
|
2450
2450
|
/* @__PURE__ */ React__default.createElement(InlineComboboxContext.Provider, { value: contextValue }, children)
|
|
@@ -2546,14 +2546,14 @@ const InlineComboboxEmpty = ({
|
|
|
2546
2546
|
}) => {
|
|
2547
2547
|
const { setHasEmpty } = useContext(InlineComboboxContext);
|
|
2548
2548
|
const store = useComboboxContext();
|
|
2549
|
-
const
|
|
2549
|
+
const items = store.useState("items");
|
|
2550
2550
|
useEffect(() => {
|
|
2551
2551
|
setHasEmpty(true);
|
|
2552
2552
|
return () => {
|
|
2553
2553
|
setHasEmpty(false);
|
|
2554
2554
|
};
|
|
2555
2555
|
}, [setHasEmpty]);
|
|
2556
|
-
if (
|
|
2556
|
+
if (items.length > 0)
|
|
2557
2557
|
return null;
|
|
2558
2558
|
return /* @__PURE__ */ React__default.createElement(
|
|
2559
2559
|
"div",
|
|
@@ -2563,28 +2563,80 @@ const InlineComboboxEmpty = ({
|
|
|
2563
2563
|
children
|
|
2564
2564
|
);
|
|
2565
2565
|
};
|
|
2566
|
-
const
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2566
|
+
const ToolbarContext = createContext(
|
|
2567
|
+
void 0
|
|
2568
|
+
);
|
|
2569
|
+
const ToolbarProvider = ({
|
|
2570
|
+
tinaForm,
|
|
2571
|
+
templates,
|
|
2572
|
+
overrides,
|
|
2573
|
+
children
|
|
2574
|
+
}) => {
|
|
2575
|
+
const configured = !Array.isArray(overrides) ? overrides == null ? void 0 : overrides.headingLevels : void 0;
|
|
2576
|
+
const headingLevelsConfigured = Array.isArray(configured);
|
|
2577
|
+
const headingLevels = useMemo(
|
|
2578
|
+
() => configured ? normalizeHeadingLevels(configured) : ALL_HEADING_LEVELS,
|
|
2579
|
+
[configured]
|
|
2580
|
+
);
|
|
2581
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
2582
|
+
ToolbarContext.Provider,
|
|
2583
|
+
{
|
|
2584
|
+
value: {
|
|
2585
|
+
tinaForm,
|
|
2586
|
+
templates,
|
|
2587
|
+
overrides,
|
|
2588
|
+
headingLevels,
|
|
2589
|
+
headingLevelsConfigured
|
|
2590
|
+
}
|
|
2571
2591
|
},
|
|
2592
|
+
children
|
|
2593
|
+
);
|
|
2594
|
+
};
|
|
2595
|
+
const useToolbarContext = () => {
|
|
2596
|
+
const context = useContext(ToolbarContext);
|
|
2597
|
+
if (!context) {
|
|
2598
|
+
throw new Error("useToolbarContext must be used within a ToolbarProvider");
|
|
2599
|
+
}
|
|
2600
|
+
return context;
|
|
2601
|
+
};
|
|
2602
|
+
const headingRulesByLevel = {
|
|
2603
|
+
h1: {
|
|
2604
|
+
icon: Icons.h1,
|
|
2605
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h1),
|
|
2572
2606
|
value: "Heading 1"
|
|
2573
2607
|
},
|
|
2574
|
-
{
|
|
2608
|
+
h2: {
|
|
2575
2609
|
icon: Icons.h2,
|
|
2576
|
-
onSelect: (editor) =>
|
|
2577
|
-
editor.tf.toggleBlock(HEADING_KEYS.h2);
|
|
2578
|
-
},
|
|
2610
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h2),
|
|
2579
2611
|
value: "Heading 2"
|
|
2580
2612
|
},
|
|
2581
|
-
{
|
|
2613
|
+
h3: {
|
|
2582
2614
|
icon: Icons.h3,
|
|
2583
|
-
onSelect: (editor) =>
|
|
2584
|
-
editor.tf.toggleBlock(HEADING_KEYS.h3);
|
|
2585
|
-
},
|
|
2615
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h3),
|
|
2586
2616
|
value: "Heading 3"
|
|
2587
2617
|
},
|
|
2618
|
+
h4: {
|
|
2619
|
+
icon: Icons.h4,
|
|
2620
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h4),
|
|
2621
|
+
value: "Heading 4"
|
|
2622
|
+
},
|
|
2623
|
+
h5: {
|
|
2624
|
+
icon: Icons.h5,
|
|
2625
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h5),
|
|
2626
|
+
value: "Heading 5"
|
|
2627
|
+
},
|
|
2628
|
+
h6: {
|
|
2629
|
+
icon: Icons.h6,
|
|
2630
|
+
onSelect: (editor) => editor.tf.toggleBlock(HEADING_KEYS.h6),
|
|
2631
|
+
value: "Heading 6"
|
|
2632
|
+
}
|
|
2633
|
+
};
|
|
2634
|
+
const DEFAULT_SLASH_HEADING_LEVELS = [
|
|
2635
|
+
"h1",
|
|
2636
|
+
"h2",
|
|
2637
|
+
"h3"
|
|
2638
|
+
];
|
|
2639
|
+
const listRules = [
|
|
2588
2640
|
{
|
|
2589
2641
|
icon: Icons.ul,
|
|
2590
2642
|
keywords: ["ul", "unordered list"],
|
|
@@ -2605,6 +2657,12 @@ const rules = [
|
|
|
2605
2657
|
const SlashInputElement = withRef(
|
|
2606
2658
|
({ className, ...props }, ref) => {
|
|
2607
2659
|
const { children, editor, element } = props;
|
|
2660
|
+
const { headingLevels, headingLevelsConfigured } = useToolbarContext();
|
|
2661
|
+
const slashHeadingLevels = headingLevelsConfigured ? headingLevels : DEFAULT_SLASH_HEADING_LEVELS;
|
|
2662
|
+
const rules = [
|
|
2663
|
+
...slashHeadingLevels.map((level) => headingRulesByLevel[level]),
|
|
2664
|
+
...listRules
|
|
2665
|
+
];
|
|
2608
2666
|
useEffect(() => {
|
|
2609
2667
|
captureEvent(SlashCommandOpenedEvent);
|
|
2610
2668
|
}, []);
|
|
@@ -4426,7 +4484,7 @@ const DropdownButton = React.forwardRef(
|
|
|
4426
4484
|
children,
|
|
4427
4485
|
className = "",
|
|
4428
4486
|
onMainAction,
|
|
4429
|
-
items
|
|
4487
|
+
items,
|
|
4430
4488
|
showSplitButton = true,
|
|
4431
4489
|
...props
|
|
4432
4490
|
}, ref) => {
|
|
@@ -4453,7 +4511,7 @@ const DropdownButton = React.forwardRef(
|
|
|
4453
4511
|
)
|
|
4454
4512
|
}
|
|
4455
4513
|
)
|
|
4456
|
-
)), /* @__PURE__ */ React.createElement(DropdownMenuContent, { align: "end", side: "bottom", className: "z-[100000]" },
|
|
4514
|
+
)), /* @__PURE__ */ React.createElement(DropdownMenuContent, { align: "end", side: "bottom", className: "z-[100000]" }, items.map((item, index) => /* @__PURE__ */ React.createElement(
|
|
4457
4515
|
DropdownMenuItem,
|
|
4458
4516
|
{
|
|
4459
4517
|
key: index,
|
|
@@ -4500,7 +4558,7 @@ const DropdownButton = React.forwardRef(
|
|
|
4500
4558
|
style: { fill: "none" }
|
|
4501
4559
|
}
|
|
4502
4560
|
)
|
|
4503
|
-
)), /* @__PURE__ */ React.createElement(DropdownMenuContent, { align: "end", side: "bottom" },
|
|
4561
|
+
)), /* @__PURE__ */ React.createElement(DropdownMenuContent, { align: "end", side: "bottom" }, items.map((item, index) => {
|
|
4504
4562
|
var _a;
|
|
4505
4563
|
return /* @__PURE__ */ React.createElement(React.Fragment, { key: index }, /* @__PURE__ */ React.createElement(
|
|
4506
4564
|
DropdownMenuItem,
|
|
@@ -4511,7 +4569,7 @@ const DropdownButton = React.forwardRef(
|
|
|
4511
4569
|
},
|
|
4512
4570
|
item.icon && item.icon,
|
|
4513
4571
|
item.label
|
|
4514
|
-
), item.variant === "destructive" && index <
|
|
4572
|
+
), item.variant === "destructive" && index < items.length - 1 && ((_a = items[index + 1]) == null ? void 0 : _a.variant) !== "destructive" && /* @__PURE__ */ React.createElement(DropdownMenuSeparator, null));
|
|
4515
4573
|
}))));
|
|
4516
4574
|
}
|
|
4517
4575
|
);
|
|
@@ -4633,10 +4691,10 @@ const Draggable = ({
|
|
|
4633
4691
|
));
|
|
4634
4692
|
};
|
|
4635
4693
|
const SortableProvider = ({
|
|
4636
|
-
items
|
|
4694
|
+
items,
|
|
4637
4695
|
children
|
|
4638
4696
|
}) => {
|
|
4639
|
-
return /* @__PURE__ */ React__default.createElement(SortableContext, { items
|
|
4697
|
+
return /* @__PURE__ */ React__default.createElement(SortableContext, { items, strategy: verticalListSortingStrategy }, children);
|
|
4640
4698
|
};
|
|
4641
4699
|
const Dismissible = ({
|
|
4642
4700
|
onDismiss,
|
|
@@ -5590,6 +5648,26 @@ const absoluteImgURL = (str) => {
|
|
|
5590
5648
|
return str;
|
|
5591
5649
|
return `${window.location.origin}${str}`;
|
|
5592
5650
|
};
|
|
5651
|
+
const MAX_BASENAME_LENGTH = 200;
|
|
5652
|
+
const sanitizeFilename = (filename) => {
|
|
5653
|
+
if (!filename)
|
|
5654
|
+
return "file";
|
|
5655
|
+
const normalized = filename.normalize("NFC");
|
|
5656
|
+
const justName = normalized.split(/[\\/]/).pop() || "";
|
|
5657
|
+
const lastDot = justName.lastIndexOf(".");
|
|
5658
|
+
const hasExt = lastDot > 0 && lastDot < justName.length - 1;
|
|
5659
|
+
const rawBase = hasExt ? justName.slice(0, lastDot) : justName;
|
|
5660
|
+
const rawExt = hasExt ? justName.slice(lastDot) : "";
|
|
5661
|
+
const clean2 = (input) => input.replace(/\s+/g, "-").replace(/[\x00-\x1F\x7F]/g, "").replace(/[<>:"|?*#%&]/g, "-").replace(/-+/g, "-");
|
|
5662
|
+
let base = clean2(rawBase).replace(/^[.\-]+|[.\-]+$/g, "");
|
|
5663
|
+
const ext = clean2(rawExt);
|
|
5664
|
+
if (!base)
|
|
5665
|
+
base = "file";
|
|
5666
|
+
if (base.length > MAX_BASENAME_LENGTH) {
|
|
5667
|
+
base = base.slice(0, MAX_BASENAME_LENGTH).replace(/[.\-]+$/, "") || "file";
|
|
5668
|
+
}
|
|
5669
|
+
return `${base}${ext}`;
|
|
5670
|
+
};
|
|
5593
5671
|
const { useDropzone: useDropzone$1 } = dropzone;
|
|
5594
5672
|
const StyledImage = ({ src }) => {
|
|
5595
5673
|
const isSvg = /\.svg$/.test(src);
|
|
@@ -6198,7 +6276,7 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6198
6276
|
}
|
|
6199
6277
|
if (field.openFormOnCreate) {
|
|
6200
6278
|
const state = tinaForm.finalForm.getState();
|
|
6201
|
-
const newIndex = field.addItemBehavior === "prepend" ? 0 :
|
|
6279
|
+
const newIndex = field.addItemBehavior === "prepend" ? 0 : items.length;
|
|
6202
6280
|
if (state.invalid === true) {
|
|
6203
6281
|
cms.alerts.error("Cannot navigate away from an invalid form.");
|
|
6204
6282
|
return;
|
|
@@ -6216,7 +6294,7 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6216
6294
|
});
|
|
6217
6295
|
}
|
|
6218
6296
|
}, [form, field]);
|
|
6219
|
-
const
|
|
6297
|
+
const items = input.value || [];
|
|
6220
6298
|
const itemProps = React__default.useCallback(
|
|
6221
6299
|
(item) => {
|
|
6222
6300
|
if (!field.itemProps)
|
|
@@ -6225,8 +6303,8 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6225
6303
|
},
|
|
6226
6304
|
[field.itemProps]
|
|
6227
6305
|
);
|
|
6228
|
-
const isMax =
|
|
6229
|
-
const isMin =
|
|
6306
|
+
const isMax = items.length >= (field.max || Number.POSITIVE_INFINITY);
|
|
6307
|
+
const isMin = items.length <= (field.min || 0);
|
|
6230
6308
|
const fixedLength = field.min === field.max;
|
|
6231
6309
|
return /* @__PURE__ */ React__default.createElement(
|
|
6232
6310
|
ListFieldMeta,
|
|
@@ -6249,12 +6327,12 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6249
6327
|
/* @__PURE__ */ React__default.createElement(AddIcon, { className: "w-5/6 h-auto" })
|
|
6250
6328
|
)
|
|
6251
6329
|
},
|
|
6252
|
-
/* @__PURE__ */ React__default.createElement(ListPanel, null, /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React__default.createElement("div", { ref: provider.innerRef },
|
|
6330
|
+
/* @__PURE__ */ React__default.createElement(ListPanel, null, /* @__PURE__ */ React__default.createElement("div", null, /* @__PURE__ */ React__default.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React__default.createElement("div", { ref: provider.innerRef }, items.length === 0 && /* @__PURE__ */ React__default.createElement(EmptyList, null), /* @__PURE__ */ React__default.createElement(
|
|
6253
6331
|
SortableProvider,
|
|
6254
6332
|
{
|
|
6255
|
-
items:
|
|
6333
|
+
items: items.map((_, index2) => `${field.name}.${index2}`)
|
|
6256
6334
|
},
|
|
6257
|
-
|
|
6335
|
+
items.map((item, index2) => /* @__PURE__ */ React__default.createElement(
|
|
6258
6336
|
Item$1,
|
|
6259
6337
|
{
|
|
6260
6338
|
key: index2,
|
|
@@ -6833,9 +6911,9 @@ const Blocks = ({
|
|
|
6833
6911
|
},
|
|
6834
6912
|
[field.name, form.mutators]
|
|
6835
6913
|
);
|
|
6836
|
-
const
|
|
6837
|
-
const isMax =
|
|
6838
|
-
const isMin =
|
|
6914
|
+
const items = input.value || [];
|
|
6915
|
+
const isMax = items.length >= (field.max || Infinity);
|
|
6916
|
+
const isMin = items.length <= (field.min || 0);
|
|
6839
6917
|
const fixedLength = field.min === field.max;
|
|
6840
6918
|
return /* @__PURE__ */ React.createElement(
|
|
6841
6919
|
ListFieldMeta,
|
|
@@ -6857,12 +6935,12 @@ const Blocks = ({
|
|
|
6857
6935
|
}
|
|
6858
6936
|
))
|
|
6859
6937
|
},
|
|
6860
|
-
/* @__PURE__ */ React.createElement(ListPanel, null, /* @__PURE__ */ React.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React.createElement("div", { ref: provider.innerRef, className: "edit-page--list-parent" },
|
|
6938
|
+
/* @__PURE__ */ React.createElement(ListPanel, null, /* @__PURE__ */ React.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React.createElement("div", { ref: provider.innerRef, className: "edit-page--list-parent" }, items.length === 0 && /* @__PURE__ */ React.createElement(EmptyList, null), /* @__PURE__ */ React.createElement(
|
|
6861
6939
|
SortableProvider,
|
|
6862
6940
|
{
|
|
6863
|
-
items:
|
|
6941
|
+
items: items.map((_, index2) => `${field.name}.${index2}`)
|
|
6864
6942
|
},
|
|
6865
|
-
|
|
6943
|
+
items.map((block, index2) => {
|
|
6866
6944
|
const template = field.templates[block._template];
|
|
6867
6945
|
if (!template) {
|
|
6868
6946
|
return /* @__PURE__ */ React.createElement(
|
|
@@ -7014,7 +7092,7 @@ const List = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
7014
7092
|
form.mutators.push(field.name, newItem);
|
|
7015
7093
|
}
|
|
7016
7094
|
}, [form, field]);
|
|
7017
|
-
const
|
|
7095
|
+
const items = input.value || [];
|
|
7018
7096
|
const itemProps = React.useCallback(
|
|
7019
7097
|
(item) => {
|
|
7020
7098
|
if (!field.itemProps)
|
|
@@ -7023,8 +7101,8 @@ const List = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
7023
7101
|
},
|
|
7024
7102
|
[field.itemProps]
|
|
7025
7103
|
);
|
|
7026
|
-
const isMax =
|
|
7027
|
-
const isMin =
|
|
7104
|
+
const isMax = items.length >= (field == null ? void 0 : field.max);
|
|
7105
|
+
const isMin = items.length <= (field == null ? void 0 : field.min);
|
|
7028
7106
|
const fixedLength = (field == null ? void 0 : field.min) === (field == null ? void 0 : field.max);
|
|
7029
7107
|
return /* @__PURE__ */ React.createElement(
|
|
7030
7108
|
ListFieldMeta,
|
|
@@ -7046,12 +7124,12 @@ const List = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
7046
7124
|
/* @__PURE__ */ React.createElement(AddIcon, { className: "w-5/6 h-auto" })
|
|
7047
7125
|
)
|
|
7048
7126
|
},
|
|
7049
|
-
/* @__PURE__ */ React.createElement(ListPanel, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React.createElement("div", { ref: provider.innerRef },
|
|
7127
|
+
/* @__PURE__ */ React.createElement(ListPanel, null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Droppable, { droppableId: field.name, type: field.name }, (provider) => /* @__PURE__ */ React.createElement("div", { ref: provider.innerRef }, items.length === 0 && /* @__PURE__ */ React.createElement(EmptyList, null), /* @__PURE__ */ React.createElement(
|
|
7050
7128
|
SortableProvider,
|
|
7051
7129
|
{
|
|
7052
|
-
items:
|
|
7130
|
+
items: items.map((_, index2) => `${field.name}.${index2}`)
|
|
7053
7131
|
},
|
|
7054
|
-
|
|
7132
|
+
items.map((item, index2) => /* @__PURE__ */ React.createElement(
|
|
7055
7133
|
Item,
|
|
7056
7134
|
{
|
|
7057
7135
|
key: index2,
|
|
@@ -7335,8 +7413,8 @@ const TextFieldPlugin = {
|
|
|
7335
7413
|
const path = field.name.split(".");
|
|
7336
7414
|
const fieldName = path[path.length - 1];
|
|
7337
7415
|
const parent = path.slice(0, path.length - 2);
|
|
7338
|
-
const
|
|
7339
|
-
if (((_a =
|
|
7416
|
+
const items = get(allValues, parent);
|
|
7417
|
+
if (((_a = items == null ? void 0 : items.filter((item) => item[fieldName] === value)) == null ? void 0 : _a.length) > 1) {
|
|
7340
7418
|
return "Item with this unique id already exists";
|
|
7341
7419
|
}
|
|
7342
7420
|
}
|
|
@@ -7369,7 +7447,7 @@ const TagsField = wrapFieldsWithMeta(({ input, field, form, tinaForm }) => {
|
|
|
7369
7447
|
},
|
|
7370
7448
|
[form, field.name]
|
|
7371
7449
|
);
|
|
7372
|
-
const
|
|
7450
|
+
const items = input.value || [];
|
|
7373
7451
|
const ref = React.useRef(null);
|
|
7374
7452
|
React.useEffect(() => {
|
|
7375
7453
|
if (ref.current && field.experimental_focusIntent) {
|
|
@@ -7402,7 +7480,7 @@ const TagsField = wrapFieldsWithMeta(({ input, field, form, tinaForm }) => {
|
|
|
7402
7480
|
className: "flex-shrink-0"
|
|
7403
7481
|
},
|
|
7404
7482
|
/* @__PURE__ */ React.createElement(AddIcon, { className: "w-5/6 h-auto" })
|
|
7405
|
-
)), /* @__PURE__ */ React.createElement("span", { className: "flex gap-2 flex-wrap mt-2 mb-0" },
|
|
7483
|
+
)), /* @__PURE__ */ React.createElement("span", { className: "flex gap-2 flex-wrap mt-2 mb-0" }, items.length === 0 && /* @__PURE__ */ React.createElement("span", { className: "text-gray-300 text-sm italic" }, "No tags"), items.map((tag, index) => /* @__PURE__ */ React.createElement(Tag, { key: tag, tinaForm, field, index }, tag))));
|
|
7406
7484
|
});
|
|
7407
7485
|
const Tag = ({ tinaForm, field, index, children, ...styleProps }) => {
|
|
7408
7486
|
const removeItem = React.useCallback(() => {
|
|
@@ -9228,12 +9306,23 @@ const PullRequestCell = ({
|
|
|
9228
9306
|
}
|
|
9229
9307
|
return null;
|
|
9230
9308
|
};
|
|
9231
|
-
const tableHeadingStyle = "px-3 py-3 text-left text-xs font-bold text-gray-700 tracking-wider sticky top-0 bg-gray-100 z-20 border-b-2 border-gray-200 ";
|
|
9232
9309
|
function formatBranchName(str) {
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9310
|
+
let result = "";
|
|
9311
|
+
let replacingInvalidChars = false;
|
|
9312
|
+
for (const char of str.toLowerCase()) {
|
|
9313
|
+
const code = char.charCodeAt(0);
|
|
9314
|
+
const isValid = char === "/" || char === "-" || char === "_" || code >= 48 && code <= 57 || code >= 97 && code <= 122;
|
|
9315
|
+
if (isValid) {
|
|
9316
|
+
result += char;
|
|
9317
|
+
replacingInvalidChars = false;
|
|
9318
|
+
} else if (!replacingInvalidChars) {
|
|
9319
|
+
result += "-";
|
|
9320
|
+
replacingInvalidChars = true;
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9323
|
+
return result;
|
|
9236
9324
|
}
|
|
9325
|
+
const tableHeadingStyle = "px-3 py-3 text-left text-xs font-bold text-gray-700 tracking-wider sticky top-0 bg-gray-100 z-20 border-b-2 border-gray-200 ";
|
|
9237
9326
|
const BranchSwitcher = (props) => {
|
|
9238
9327
|
const cms = useCMS$1();
|
|
9239
9328
|
const usingEditorialWorkflow = cms.api.tina.usingEditorialWorkflow;
|
|
@@ -9936,9 +10025,28 @@ class EventBus {
|
|
|
9936
10025
|
}
|
|
9937
10026
|
dispatch(event) {
|
|
9938
10027
|
if (!this.listeners)
|
|
9939
|
-
return;
|
|
10028
|
+
return false;
|
|
9940
10029
|
const listenerSnapshot = Array.from(this.listeners.values());
|
|
9941
|
-
listenerSnapshot.
|
|
10030
|
+
return listenerSnapshot.reduce(
|
|
10031
|
+
(handled, listener) => listener.handleEvent(event) || handled,
|
|
10032
|
+
false
|
|
10033
|
+
);
|
|
10034
|
+
}
|
|
10035
|
+
/**
|
|
10036
|
+
* Whether any listener *explicitly* targets `eventType`. The catch-all `'*'`
|
|
10037
|
+
* pattern does not count — callers use this to detect a purpose-built
|
|
10038
|
+
* subscriber (e.g. a mounted UI overlay) without being misled by ambient
|
|
10039
|
+
* `'*'` listeners such as the alerts bridge, which would otherwise make
|
|
10040
|
+
* {@link dispatch} report every event as "handled".
|
|
10041
|
+
*/
|
|
10042
|
+
hasExplicitListenerFor(eventType) {
|
|
10043
|
+
if (!this.listeners)
|
|
10044
|
+
return false;
|
|
10045
|
+
for (const listener of this.listeners) {
|
|
10046
|
+
if (listener.isExplicitListenerFor(eventType))
|
|
10047
|
+
return true;
|
|
10048
|
+
}
|
|
10049
|
+
return false;
|
|
9942
10050
|
}
|
|
9943
10051
|
}
|
|
9944
10052
|
class Listener {
|
|
@@ -9953,6 +10061,16 @@ class Listener {
|
|
|
9953
10061
|
}
|
|
9954
10062
|
return false;
|
|
9955
10063
|
}
|
|
10064
|
+
/**
|
|
10065
|
+
* Whether this listener explicitly targets `eventType`. Unlike
|
|
10066
|
+
* {@link watchesEvent}, the catch-all `'*'` pattern does NOT match, so this
|
|
10067
|
+
* reflects a purpose-built subscription rather than an ambient one.
|
|
10068
|
+
*/
|
|
10069
|
+
isExplicitListenerFor(eventType) {
|
|
10070
|
+
if (this.eventPattern === "*")
|
|
10071
|
+
return false;
|
|
10072
|
+
return this.watchesEvent({ type: eventType });
|
|
10073
|
+
}
|
|
9956
10074
|
watchesEvent(currentEvent) {
|
|
9957
10075
|
if (this.eventPattern === "*")
|
|
9958
10076
|
return true;
|
|
@@ -9969,23 +10087,83 @@ class Listener {
|
|
|
9969
10087
|
return !ignoresEvent;
|
|
9970
10088
|
}
|
|
9971
10089
|
}
|
|
10090
|
+
const EDITORIAL_WORKFLOW_STATUS = {
|
|
10091
|
+
QUEUED: "queued",
|
|
10092
|
+
PROCESSING: "processing",
|
|
10093
|
+
SETTING_UP: "setting_up",
|
|
10094
|
+
CREATING_BRANCH: "creating_branch",
|
|
10095
|
+
INDEXING: "indexing",
|
|
10096
|
+
CONTENT_GENERATION: "content_generation",
|
|
10097
|
+
CREATING_PR: "creating_pr",
|
|
10098
|
+
COMPLETE: "complete",
|
|
10099
|
+
ERROR: "error",
|
|
10100
|
+
TIMEOUT: "timeout"
|
|
10101
|
+
};
|
|
10102
|
+
const EDITORIAL_WORKFLOW_ERROR = {
|
|
10103
|
+
BRANCH_EXISTS: "BRANCH_EXISTS",
|
|
10104
|
+
BRANCH_HIERARCHY_CONFLICT: "BRANCH_HIERARCHY_CONFLICT",
|
|
10105
|
+
VALIDATION_FAILED: "VALIDATION_FAILED"
|
|
10106
|
+
};
|
|
10107
|
+
const getEditorialWorkflowPrTitle = (branchName) => `${branchName.replace("tina/", "").replaceAll("-", " ")} (PR from TinaCMS)`;
|
|
10108
|
+
const TARGET_BRANCH_EXISTS_ERROR = "A branch with this name already exists";
|
|
10109
|
+
const checkBranchExists = async (tinaApi, branchName, debugLabel, branchType, fallback, signal) => {
|
|
10110
|
+
try {
|
|
10111
|
+
console.debug(
|
|
10112
|
+
`[tina:branch-guard] ${debugLabel}: checking ${branchType} branch:`,
|
|
10113
|
+
branchName
|
|
10114
|
+
);
|
|
10115
|
+
const exists = await tinaApi.branchExists(branchName, { signal });
|
|
10116
|
+
console.debug(
|
|
10117
|
+
`[tina:branch-guard] ${debugLabel}: ${branchType} branch exists?`,
|
|
10118
|
+
exists
|
|
10119
|
+
);
|
|
10120
|
+
return exists;
|
|
10121
|
+
} catch (err) {
|
|
10122
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
10123
|
+
return fallback;
|
|
10124
|
+
console.error(
|
|
10125
|
+
`[tina:branch-guard] ${debugLabel}: branchExists threw, failing open:`,
|
|
10126
|
+
err
|
|
10127
|
+
);
|
|
10128
|
+
return fallback;
|
|
10129
|
+
}
|
|
10130
|
+
};
|
|
10131
|
+
const checkBaseBranchExists = async (tinaApi, baseBranch, debugLabel, signal) => checkBranchExists(tinaApi, baseBranch, debugLabel, "base", true, signal);
|
|
10132
|
+
const checkTargetBranchExists = async (tinaApi, targetBranch, debugLabel, signal) => checkBranchExists(tinaApi, targetBranch, debugLabel, "target", false, signal);
|
|
10133
|
+
const MEDIA_WORKFLOW_STEP = {
|
|
10134
|
+
BRANCH: 1,
|
|
10135
|
+
CONTENT: 2,
|
|
10136
|
+
PR: 3,
|
|
10137
|
+
COMPLETE: 4
|
|
10138
|
+
};
|
|
10139
|
+
const MEDIA_WORKFLOW_STATUS_TO_STEP = {
|
|
10140
|
+
[EDITORIAL_WORKFLOW_STATUS.SETTING_UP]: MEDIA_WORKFLOW_STEP.BRANCH,
|
|
10141
|
+
[EDITORIAL_WORKFLOW_STATUS.CREATING_BRANCH]: MEDIA_WORKFLOW_STEP.BRANCH,
|
|
10142
|
+
[EDITORIAL_WORKFLOW_STATUS.INDEXING]: MEDIA_WORKFLOW_STEP.CONTENT,
|
|
10143
|
+
[EDITORIAL_WORKFLOW_STATUS.CONTENT_GENERATION]: MEDIA_WORKFLOW_STEP.CONTENT,
|
|
10144
|
+
[EDITORIAL_WORKFLOW_STATUS.CREATING_PR]: MEDIA_WORKFLOW_STEP.PR,
|
|
10145
|
+
[EDITORIAL_WORKFLOW_STATUS.COMPLETE]: MEDIA_WORKFLOW_STEP.COMPLETE
|
|
10146
|
+
};
|
|
9972
10147
|
const s3ErrorRegex = /<Error>.*<Code>(.+)<\/Code>.*<Message>(.+)<\/Message>.*/;
|
|
9973
10148
|
class DummyMediaStore {
|
|
9974
10149
|
constructor() {
|
|
9975
10150
|
__publicField(this, "accept", "*");
|
|
9976
10151
|
}
|
|
9977
10152
|
async persist(files2) {
|
|
9978
|
-
return files2.map(({ directory, file }) =>
|
|
9979
|
-
|
|
9980
|
-
|
|
9981
|
-
|
|
9982
|
-
|
|
9983
|
-
|
|
10153
|
+
return files2.map(({ directory, file }) => {
|
|
10154
|
+
const filename = sanitizeFilename(file.name);
|
|
10155
|
+
return {
|
|
10156
|
+
id: filename,
|
|
10157
|
+
type: "file",
|
|
10158
|
+
directory,
|
|
10159
|
+
filename
|
|
10160
|
+
};
|
|
10161
|
+
});
|
|
9984
10162
|
}
|
|
9985
10163
|
async list() {
|
|
9986
|
-
const
|
|
10164
|
+
const items = [];
|
|
9987
10165
|
return {
|
|
9988
|
-
items
|
|
10166
|
+
items,
|
|
9989
10167
|
nextOffset: 0
|
|
9990
10168
|
};
|
|
9991
10169
|
}
|
|
@@ -10003,6 +10181,9 @@ class TinaMediaStore {
|
|
|
10003
10181
|
__publicField(this, "url");
|
|
10004
10182
|
__publicField(this, "staticMedia");
|
|
10005
10183
|
__publicField(this, "isStatic");
|
|
10184
|
+
// Route assets-api calls through the created branch until indexing makes it safe to switch React branch state.
|
|
10185
|
+
__publicField(this, "workflowBranchOverride");
|
|
10186
|
+
__publicField(this, "mediaWorkflowInProgress", false);
|
|
10006
10187
|
__publicField(this, "accept", DEFAULT_MEDIA_UPLOAD_TYPES);
|
|
10007
10188
|
// allow up to 100MB uploads
|
|
10008
10189
|
__publicField(this, "maxSize", 100 * 1024 * 1024);
|
|
@@ -10042,8 +10223,8 @@ class TinaMediaStore {
|
|
|
10042
10223
|
return await this.api.authProvider.isAuthenticated();
|
|
10043
10224
|
}
|
|
10044
10225
|
/**
|
|
10045
|
-
* Returns the current branch as a single-encoded
|
|
10046
|
-
* an empty string when no branch is set.
|
|
10226
|
+
* Returns the workflow branch override or current branch as a single-encoded
|
|
10227
|
+
* query-param value, or an empty string when no branch is set.
|
|
10047
10228
|
*
|
|
10048
10229
|
* `this.api.branch` is already URL-encoded by `Client.setBranch()`, so we
|
|
10049
10230
|
* decode then re-encode here to defend against double-encoding when this
|
|
@@ -10056,6 +10237,9 @@ class TinaMediaStore {
|
|
|
10056
10237
|
* assets-api (which would route the call to a non-existent staging path).
|
|
10057
10238
|
*/
|
|
10058
10239
|
encodedBranchParam() {
|
|
10240
|
+
if (this.workflowBranchOverride) {
|
|
10241
|
+
return encodeURIComponent(this.workflowBranchOverride);
|
|
10242
|
+
}
|
|
10059
10243
|
if (!this.api.branch)
|
|
10060
10244
|
return "";
|
|
10061
10245
|
const decoded = decodeURIComponent(this.api.branch);
|
|
@@ -10063,66 +10247,297 @@ class TinaMediaStore {
|
|
|
10063
10247
|
return "";
|
|
10064
10248
|
return encodeURIComponent(decoded);
|
|
10065
10249
|
}
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10250
|
+
shortStableHash(input) {
|
|
10251
|
+
let hash = 2166136261;
|
|
10252
|
+
for (let index = 0; index < input.length; index++) {
|
|
10253
|
+
hash ^= input.charCodeAt(index);
|
|
10254
|
+
hash = Math.imul(hash, 16777619);
|
|
10069
10255
|
}
|
|
10256
|
+
return (hash >>> 0).toString(36);
|
|
10257
|
+
}
|
|
10258
|
+
trimEdges(value, char) {
|
|
10259
|
+
let start = 0;
|
|
10260
|
+
let end = value.length;
|
|
10261
|
+
while (start < end && value[start] === char) {
|
|
10262
|
+
start++;
|
|
10263
|
+
}
|
|
10264
|
+
while (end > start && value[end - 1] === char) {
|
|
10265
|
+
end--;
|
|
10266
|
+
}
|
|
10267
|
+
return value.slice(start, end);
|
|
10268
|
+
}
|
|
10269
|
+
branchSlugForMediaPath(directory, filename) {
|
|
10270
|
+
const trimmedDirectory = this.trimEdges(directory ?? "", "/");
|
|
10271
|
+
const rawPath = [trimmedDirectory, filename].filter(Boolean).join("/");
|
|
10272
|
+
const flattened = rawPath.replaceAll("/", "-");
|
|
10273
|
+
const slug = this.trimEdges(formatBranchName(flattened), "-");
|
|
10274
|
+
if (!slug)
|
|
10275
|
+
return `asset-${this.shortStableHash(rawPath || "root")}`;
|
|
10276
|
+
return rawPath !== rawPath.toLowerCase() ? `${slug}-${this.shortStableHash(rawPath)}` : slug;
|
|
10277
|
+
}
|
|
10278
|
+
/** Joins a directory and filename into a normalized `dir/file` repo path. */
|
|
10279
|
+
joinMediaPath(directory, filename) {
|
|
10280
|
+
const dir = this.trimEdges(directory ?? "", "/");
|
|
10281
|
+
return dir && dir !== "/" ? `${dir}/${filename ?? ""}` : filename ?? "";
|
|
10282
|
+
}
|
|
10283
|
+
branchQueryParam() {
|
|
10070
10284
|
const encodedBranch = this.encodedBranchParam();
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
const path = `${directory && directory !== "/" ? `${directory}/${item.file.name}` : item.file.name}`;
|
|
10078
|
-
const res = await this.api.authProvider.fetchWithToken(
|
|
10079
|
-
`${this.url}/upload_url/${path}${branchQuery}`,
|
|
10080
|
-
{ method: "GET" }
|
|
10285
|
+
return encodedBranch ? `?branch=${encodedBranch}` : "";
|
|
10286
|
+
}
|
|
10287
|
+
requestMediaBranchChoice(branchName, baseBranch, opType, repoPath) {
|
|
10288
|
+
if (!this.cms.events.hasExplicitListenerFor("media:workflow:confirm-branch")) {
|
|
10289
|
+
throw new Error(
|
|
10290
|
+
"Cannot start a media editorial workflow: no branch prompt is mounted. Ensure <MediaWorkflowOverlay /> is rendered (TinaCloudProvider mounts it automatically)."
|
|
10081
10291
|
);
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10292
|
+
}
|
|
10293
|
+
return new Promise((resolve) => {
|
|
10294
|
+
this.cms.events.dispatch({
|
|
10295
|
+
type: "media:workflow:confirm-branch",
|
|
10296
|
+
branchName,
|
|
10297
|
+
baseBranch,
|
|
10298
|
+
onConfirm: async (selectedBranchName) => {
|
|
10299
|
+
const context = await this.prepareMediaBranch(
|
|
10300
|
+
selectedBranchName,
|
|
10301
|
+
baseBranch,
|
|
10302
|
+
opType,
|
|
10303
|
+
repoPath
|
|
10304
|
+
);
|
|
10305
|
+
resolve({
|
|
10306
|
+
kind: "workflow",
|
|
10307
|
+
context
|
|
10308
|
+
});
|
|
10309
|
+
},
|
|
10310
|
+
onCancel: () => resolve({ kind: "cancelled" }),
|
|
10311
|
+
onSaveToProtectedBranch: () => resolve({ kind: "direct" })
|
|
10312
|
+
});
|
|
10313
|
+
});
|
|
10314
|
+
}
|
|
10315
|
+
async prepareMediaBranch(branchName, baseBranch, opType, repoPath) {
|
|
10316
|
+
if (this.mediaWorkflowInProgress) {
|
|
10317
|
+
throw new Error("A media workflow is already in progress.");
|
|
10318
|
+
}
|
|
10319
|
+
this.mediaWorkflowInProgress = true;
|
|
10320
|
+
try {
|
|
10321
|
+
this.cms.events.dispatch({
|
|
10322
|
+
type: "media:workflow:start",
|
|
10323
|
+
branchName,
|
|
10324
|
+
baseBranch
|
|
10325
|
+
});
|
|
10326
|
+
const workflow = await this.api.startMediaEditorialWorkflow({
|
|
10327
|
+
branchName,
|
|
10328
|
+
baseBranch,
|
|
10329
|
+
prTitle: getEditorialWorkflowPrTitle(branchName),
|
|
10330
|
+
operation: opType,
|
|
10331
|
+
repoPath
|
|
10332
|
+
});
|
|
10333
|
+
const branchContext = {
|
|
10334
|
+
branchName: workflow.branchName || branchName,
|
|
10335
|
+
baseBranch,
|
|
10336
|
+
requestId: workflow.requestId
|
|
10337
|
+
};
|
|
10338
|
+
this.workflowBranchOverride = branchContext.branchName;
|
|
10339
|
+
return branchContext;
|
|
10340
|
+
} catch (err) {
|
|
10341
|
+
this.resetWorkflowState();
|
|
10342
|
+
throw err;
|
|
10343
|
+
}
|
|
10344
|
+
}
|
|
10345
|
+
resetWorkflowState() {
|
|
10346
|
+
this.workflowBranchOverride = void 0;
|
|
10347
|
+
this.mediaWorkflowInProgress = false;
|
|
10348
|
+
}
|
|
10349
|
+
async finalizeMediaWorkflow(branchContext, onCatalogued) {
|
|
10350
|
+
try {
|
|
10351
|
+
const result = await this.api.waitForEditorialWorkflowStatus(
|
|
10352
|
+
branchContext.requestId,
|
|
10353
|
+
(status) => {
|
|
10354
|
+
const step = MEDIA_WORKFLOW_STATUS_TO_STEP[status.status];
|
|
10355
|
+
if (step) {
|
|
10356
|
+
this.cms.events.dispatch({
|
|
10357
|
+
type: "media:workflow:step",
|
|
10358
|
+
step
|
|
10359
|
+
});
|
|
10360
|
+
}
|
|
10096
10361
|
}
|
|
10362
|
+
);
|
|
10363
|
+
if (onCatalogued)
|
|
10364
|
+
await onCatalogued();
|
|
10365
|
+
this.resetWorkflowState();
|
|
10366
|
+
this.cms.events.dispatch({
|
|
10367
|
+
type: "media:workflow:complete",
|
|
10368
|
+
branchName: result.branchName || branchContext.branchName
|
|
10097
10369
|
});
|
|
10098
|
-
if (
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10370
|
+
if (result.warning) {
|
|
10371
|
+
this.cms.alerts.warn(result.warning, 0);
|
|
10372
|
+
}
|
|
10373
|
+
this.cms.alerts.success(
|
|
10374
|
+
`Branch created successfully - Pull Request at ${(result == null ? void 0 : result.pullRequestUrl) || ""}`,
|
|
10375
|
+
0
|
|
10376
|
+
);
|
|
10377
|
+
this.cms.events.dispatch({ type: "media:workflow:finish" });
|
|
10378
|
+
} catch (err) {
|
|
10379
|
+
this.resetWorkflowState();
|
|
10380
|
+
this.dispatchMediaWorkflowError(err);
|
|
10381
|
+
}
|
|
10382
|
+
}
|
|
10383
|
+
dispatchMediaWorkflowError(err) {
|
|
10384
|
+
this.cms.events.dispatch({
|
|
10385
|
+
type: "media:workflow:error",
|
|
10386
|
+
message: err instanceof Error ? err.message : String(err)
|
|
10387
|
+
});
|
|
10388
|
+
}
|
|
10389
|
+
async runMediaOpWithWorkflow(decision, op) {
|
|
10390
|
+
if (decision.kind !== "workflow")
|
|
10391
|
+
return op();
|
|
10392
|
+
try {
|
|
10393
|
+
const result = await op();
|
|
10394
|
+
await this.finalizeMediaWorkflow(decision.context);
|
|
10395
|
+
return result;
|
|
10396
|
+
} catch (err) {
|
|
10397
|
+
this.resetWorkflowState();
|
|
10398
|
+
this.cms.events.dispatch({ type: "media:workflow:finish" });
|
|
10399
|
+
throw err;
|
|
10400
|
+
}
|
|
10401
|
+
}
|
|
10402
|
+
async prepareProtectedMediaBranch(opType, directory, filename) {
|
|
10403
|
+
if (!this.api.usingProtectedBranch())
|
|
10404
|
+
return { kind: "direct" };
|
|
10405
|
+
const baseBranch = decodeURIComponent(this.api.branch || "");
|
|
10406
|
+
const mediaSlug = this.branchSlugForMediaPath(directory, filename);
|
|
10407
|
+
const branchName = `media-${opType}-${mediaSlug}`;
|
|
10408
|
+
const repoFilename = opType === "upload" && filename ? sanitizeFilename(filename) : filename;
|
|
10409
|
+
const repoPath = this.joinMediaPath(directory, repoFilename);
|
|
10410
|
+
return this.requestMediaBranchChoice(
|
|
10411
|
+
branchName,
|
|
10412
|
+
baseBranch,
|
|
10413
|
+
opType,
|
|
10414
|
+
repoPath
|
|
10415
|
+
);
|
|
10416
|
+
}
|
|
10417
|
+
async waitForRequestStatus(requestId, timeoutMessage) {
|
|
10418
|
+
const startTime = Date.now();
|
|
10419
|
+
while (true) {
|
|
10420
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
10421
|
+
const { error: error2, message } = await this.api.getRequestStatus(requestId);
|
|
10422
|
+
if (error2 !== void 0) {
|
|
10423
|
+
if (error2) {
|
|
10424
|
+
throw new Error(message);
|
|
10104
10425
|
} else {
|
|
10105
|
-
|
|
10426
|
+
return;
|
|
10106
10427
|
}
|
|
10107
10428
|
}
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
10111
|
-
const { error: error2, message } = await this.api.getRequestStatus(requestId);
|
|
10112
|
-
if (error2 !== void 0) {
|
|
10113
|
-
if (error2) {
|
|
10114
|
-
throw new Error(message);
|
|
10115
|
-
} else {
|
|
10116
|
-
break;
|
|
10117
|
-
}
|
|
10118
|
-
}
|
|
10119
|
-
if (Date.now() - updateStartTime > 3e4) {
|
|
10120
|
-
throw new Error("Time out waiting for upload to complete");
|
|
10121
|
-
}
|
|
10429
|
+
if (Date.now() - startTime > 3e4) {
|
|
10430
|
+
throw new Error(timeoutMessage);
|
|
10122
10431
|
}
|
|
10123
10432
|
}
|
|
10433
|
+
}
|
|
10434
|
+
async persist_cloud(media) {
|
|
10435
|
+
if (media.length === 0) {
|
|
10436
|
+
return [];
|
|
10437
|
+
}
|
|
10438
|
+
if (!await this.isAuthenticated()) {
|
|
10439
|
+
return [];
|
|
10440
|
+
}
|
|
10441
|
+
const firstItem = media[0];
|
|
10442
|
+
const decision = await this.prepareProtectedMediaBranch(
|
|
10443
|
+
"upload",
|
|
10444
|
+
firstItem.directory,
|
|
10445
|
+
firstItem.file.name
|
|
10446
|
+
);
|
|
10447
|
+
if (decision.kind === "cancelled")
|
|
10448
|
+
return [];
|
|
10449
|
+
if (decision.kind === "workflow") {
|
|
10450
|
+
return this.persistCloudViaWorkflow(media, decision.context);
|
|
10451
|
+
}
|
|
10452
|
+
const branchQuery = this.branchQueryParam();
|
|
10453
|
+
for (const item of media) {
|
|
10454
|
+
await this.uploadCloudMediaItem(item, branchQuery, {
|
|
10455
|
+
waitForStatus: true
|
|
10456
|
+
});
|
|
10457
|
+
}
|
|
10124
10458
|
return this.fetchUploadedEntries(media);
|
|
10125
10459
|
}
|
|
10460
|
+
/**
|
|
10461
|
+
* Uploads assets through the editorial workflow. The asset is staged, the
|
|
10462
|
+
* server-side workflow catalogues it in the new branch's media index, and
|
|
10463
|
+
* only then do we list it — while the branch override still routes list
|
|
10464
|
+
* calls to the workflow branch, so the freshly uploaded item is returned to
|
|
10465
|
+
* the caller (and added to the media manager) without needing a manual
|
|
10466
|
+
* refresh.
|
|
10467
|
+
*/
|
|
10468
|
+
async persistCloudViaWorkflow(media, branchContext) {
|
|
10469
|
+
try {
|
|
10470
|
+
const branchQuery = this.branchQueryParam();
|
|
10471
|
+
for (const item of media) {
|
|
10472
|
+
await this.uploadCloudMediaItem(item, branchQuery, {
|
|
10473
|
+
waitForStatus: false
|
|
10474
|
+
});
|
|
10475
|
+
}
|
|
10476
|
+
let entries = [];
|
|
10477
|
+
await this.finalizeMediaWorkflow(branchContext, async () => {
|
|
10478
|
+
entries = await this.fetchUploadedEntries(media);
|
|
10479
|
+
});
|
|
10480
|
+
return entries;
|
|
10481
|
+
} catch (err) {
|
|
10482
|
+
this.resetWorkflowState();
|
|
10483
|
+
this.cms.events.dispatch({ type: "media:workflow:finish" });
|
|
10484
|
+
throw err;
|
|
10485
|
+
}
|
|
10486
|
+
}
|
|
10487
|
+
async uploadCloudMediaItem(item, branchQuery, { waitForStatus = true } = {}) {
|
|
10488
|
+
const path = this.joinMediaPath(
|
|
10489
|
+
item.directory,
|
|
10490
|
+
sanitizeFilename(item.file.name)
|
|
10491
|
+
);
|
|
10492
|
+
const res = await this.api.authProvider.fetchWithToken(
|
|
10493
|
+
`${this.url}/upload_url/${path}${branchQuery}`,
|
|
10494
|
+
{ method: "GET" }
|
|
10495
|
+
);
|
|
10496
|
+
if (res.status === 412) {
|
|
10497
|
+
const { message = "Unexpected error generating upload url" } = await res.json();
|
|
10498
|
+
throw new Error(message);
|
|
10499
|
+
}
|
|
10500
|
+
const { signedUrl, requestId } = await res.json();
|
|
10501
|
+
if (!signedUrl) {
|
|
10502
|
+
throw new Error("Unexpected error generating upload url");
|
|
10503
|
+
}
|
|
10504
|
+
const uploadRes = await this.fetchFunction(signedUrl, {
|
|
10505
|
+
method: "PUT",
|
|
10506
|
+
body: item.file,
|
|
10507
|
+
headers: {
|
|
10508
|
+
"Content-Type": item.file.type || "application/octet-stream",
|
|
10509
|
+
"Content-Length": String(item.file.size)
|
|
10510
|
+
}
|
|
10511
|
+
});
|
|
10512
|
+
if (!uploadRes.ok) {
|
|
10513
|
+
const xmlRes = await uploadRes.text();
|
|
10514
|
+
const matches = s3ErrorRegex.exec(xmlRes);
|
|
10515
|
+
console.error(xmlRes);
|
|
10516
|
+
if (!matches) {
|
|
10517
|
+
throw new Error("Unexpected error uploading media asset");
|
|
10518
|
+
} else {
|
|
10519
|
+
throw new Error(`Upload error: '${matches[2]}'`);
|
|
10520
|
+
}
|
|
10521
|
+
}
|
|
10522
|
+
if (waitForStatus) {
|
|
10523
|
+
await this.waitForRequestStatus(
|
|
10524
|
+
requestId,
|
|
10525
|
+
"Time out waiting for upload to complete"
|
|
10526
|
+
);
|
|
10527
|
+
}
|
|
10528
|
+
}
|
|
10529
|
+
groupMediaByDirectory(media) {
|
|
10530
|
+
const byDirectory = /* @__PURE__ */ new Map();
|
|
10531
|
+
for (const item of media) {
|
|
10532
|
+
let dir = item.directory || "";
|
|
10533
|
+
while (dir.endsWith("/"))
|
|
10534
|
+
dir = dir.slice(0, -1);
|
|
10535
|
+
const bucket = byDirectory.get(dir) ?? [];
|
|
10536
|
+
bucket.push(item);
|
|
10537
|
+
byDirectory.set(dir, bucket);
|
|
10538
|
+
}
|
|
10539
|
+
return byDirectory;
|
|
10540
|
+
}
|
|
10126
10541
|
/**
|
|
10127
10542
|
* Resolves the just-uploaded items to canonical `Media` entries by hitting
|
|
10128
10543
|
* the assets-api `list` endpoint, which is the source of truth for the
|
|
@@ -10136,27 +10551,19 @@ class TinaMediaStore {
|
|
|
10136
10551
|
* throwing — the upload itself already succeeded.
|
|
10137
10552
|
*/
|
|
10138
10553
|
async fetchUploadedEntries(media) {
|
|
10139
|
-
const byDirectory =
|
|
10140
|
-
for (const item of media) {
|
|
10141
|
-
let dir = item.directory || "";
|
|
10142
|
-
while (dir.endsWith("/"))
|
|
10143
|
-
dir = dir.slice(0, -1);
|
|
10144
|
-
const bucket = byDirectory.get(dir) ?? [];
|
|
10145
|
-
bucket.push(item);
|
|
10146
|
-
byDirectory.set(dir, bucket);
|
|
10147
|
-
}
|
|
10554
|
+
const byDirectory = this.groupMediaByDirectory(media);
|
|
10148
10555
|
const thumbnailSizes = [
|
|
10149
10556
|
{ w: 75, h: 75 },
|
|
10150
10557
|
{ w: 400, h: 400 },
|
|
10151
10558
|
{ w: 1e3, h: 1e3 }
|
|
10152
10559
|
];
|
|
10153
10560
|
const results = [];
|
|
10154
|
-
for (const [directory,
|
|
10561
|
+
for (const [directory, items] of byDirectory) {
|
|
10155
10562
|
let listed;
|
|
10156
10563
|
try {
|
|
10157
10564
|
listed = await this.list({
|
|
10158
10565
|
directory,
|
|
10159
|
-
limit: Math.max(100,
|
|
10566
|
+
limit: Math.max(100, items.length * 4),
|
|
10160
10567
|
thumbnailSizes
|
|
10161
10568
|
});
|
|
10162
10569
|
} catch (err) {
|
|
@@ -10169,8 +10576,8 @@ class TinaMediaStore {
|
|
|
10169
10576
|
found.set(entry.filename, entry);
|
|
10170
10577
|
}
|
|
10171
10578
|
}
|
|
10172
|
-
for (const item of
|
|
10173
|
-
const entry = found.get(item.file.name);
|
|
10579
|
+
for (const item of items) {
|
|
10580
|
+
const entry = found.get(sanitizeFilename(item.file.name));
|
|
10174
10581
|
if (entry)
|
|
10175
10582
|
results.push(entry);
|
|
10176
10583
|
}
|
|
@@ -10194,6 +10601,7 @@ class TinaMediaStore {
|
|
|
10194
10601
|
}
|
|
10195
10602
|
for (const item of media) {
|
|
10196
10603
|
const { file, directory } = item;
|
|
10604
|
+
const safeName = sanitizeFilename(file.name);
|
|
10197
10605
|
let strippedDirectory = directory;
|
|
10198
10606
|
if (strippedDirectory.startsWith("/")) {
|
|
10199
10607
|
strippedDirectory = strippedDirectory.substr(1) || "";
|
|
@@ -10202,14 +10610,14 @@ class TinaMediaStore {
|
|
|
10202
10610
|
strippedDirectory = strippedDirectory.substr(0, strippedDirectory.length - 1) || "";
|
|
10203
10611
|
}
|
|
10204
10612
|
const formData = new FormData();
|
|
10205
|
-
formData.append("file", file);
|
|
10613
|
+
formData.append("file", file, safeName);
|
|
10206
10614
|
formData.append("directory", directory);
|
|
10207
|
-
formData.append("filename",
|
|
10208
|
-
let uploadPath = `${strippedDirectory ? `${strippedDirectory}/${
|
|
10615
|
+
formData.append("filename", safeName);
|
|
10616
|
+
let uploadPath = `${strippedDirectory ? `${strippedDirectory}/${safeName}` : safeName}`;
|
|
10209
10617
|
if (uploadPath.startsWith("/")) {
|
|
10210
10618
|
uploadPath = uploadPath.substr(1);
|
|
10211
10619
|
}
|
|
10212
|
-
const filePath = `${strippedDirectory ? `${folder}${strippedDirectory}/${
|
|
10620
|
+
const filePath = `${strippedDirectory ? `${folder}${strippedDirectory}/${safeName}` : folder + safeName}`;
|
|
10213
10621
|
const res = await this.fetchFunction(`${this.url}/upload/${uploadPath}`, {
|
|
10214
10622
|
method: "POST",
|
|
10215
10623
|
body: formData
|
|
@@ -10222,8 +10630,8 @@ class TinaMediaStore {
|
|
|
10222
10630
|
if (fileRes == null ? void 0 : fileRes.success) {
|
|
10223
10631
|
const parsedRes = {
|
|
10224
10632
|
type: "file",
|
|
10225
|
-
id:
|
|
10226
|
-
filename:
|
|
10633
|
+
id: safeName,
|
|
10634
|
+
filename: safeName,
|
|
10227
10635
|
directory,
|
|
10228
10636
|
src: filePath,
|
|
10229
10637
|
thumbnails: {
|
|
@@ -10311,9 +10719,9 @@ class TinaMediaStore {
|
|
|
10311
10719
|
}
|
|
10312
10720
|
}
|
|
10313
10721
|
const { cursor, files: files2, directories } = await res.json();
|
|
10314
|
-
const
|
|
10722
|
+
const items = [];
|
|
10315
10723
|
for (const dir of directories) {
|
|
10316
|
-
|
|
10724
|
+
items.push({
|
|
10317
10725
|
type: "dir",
|
|
10318
10726
|
id: dir,
|
|
10319
10727
|
directory: options.directory || "",
|
|
@@ -10321,7 +10729,7 @@ class TinaMediaStore {
|
|
|
10321
10729
|
});
|
|
10322
10730
|
}
|
|
10323
10731
|
for (const file of files2) {
|
|
10324
|
-
|
|
10732
|
+
items.push({
|
|
10325
10733
|
directory: options.directory || "",
|
|
10326
10734
|
type: "file",
|
|
10327
10735
|
id: file.filename,
|
|
@@ -10334,42 +10742,38 @@ class TinaMediaStore {
|
|
|
10334
10742
|
});
|
|
10335
10743
|
}
|
|
10336
10744
|
return {
|
|
10337
|
-
items
|
|
10745
|
+
items,
|
|
10338
10746
|
nextOffset: cursor || 0
|
|
10339
10747
|
};
|
|
10340
10748
|
}
|
|
10341
10749
|
async delete(media) {
|
|
10342
|
-
const path =
|
|
10750
|
+
const path = this.joinMediaPath(media.directory, media.filename);
|
|
10343
10751
|
if (!this.isLocal) {
|
|
10344
10752
|
if (await this.isAuthenticated()) {
|
|
10345
|
-
const
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
{
|
|
10350
|
-
method: "DELETE"
|
|
10351
|
-
}
|
|
10753
|
+
const decision = await this.prepareProtectedMediaBranch(
|
|
10754
|
+
"delete",
|
|
10755
|
+
media.directory,
|
|
10756
|
+
media.filename
|
|
10352
10757
|
);
|
|
10353
|
-
if (
|
|
10758
|
+
if (decision.kind === "cancelled")
|
|
10759
|
+
return;
|
|
10760
|
+
await this.runMediaOpWithWorkflow(decision, async () => {
|
|
10761
|
+
const branchQuery = this.branchQueryParam();
|
|
10762
|
+
const res = await this.api.authProvider.fetchWithToken(
|
|
10763
|
+
`${this.url}/${path}${branchQuery}`,
|
|
10764
|
+
{ method: "DELETE" }
|
|
10765
|
+
);
|
|
10766
|
+
if (res.status !== 200) {
|
|
10767
|
+
throw new Error("Unexpected error deleting media asset");
|
|
10768
|
+
}
|
|
10354
10769
|
const { requestId } = await res.json();
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
if (error2) {
|
|
10361
|
-
throw new Error(message);
|
|
10362
|
-
} else {
|
|
10363
|
-
break;
|
|
10364
|
-
}
|
|
10365
|
-
}
|
|
10366
|
-
if (Date.now() - deleteStartTime > 3e4) {
|
|
10367
|
-
throw new Error("Time out waiting for delete to complete");
|
|
10368
|
-
}
|
|
10770
|
+
if (decision.kind !== "workflow") {
|
|
10771
|
+
await this.waitForRequestStatus(
|
|
10772
|
+
requestId,
|
|
10773
|
+
"Time out waiting for delete to complete"
|
|
10774
|
+
);
|
|
10369
10775
|
}
|
|
10370
|
-
}
|
|
10371
|
-
throw new Error("Unexpected error deleting media asset");
|
|
10372
|
-
}
|
|
10776
|
+
});
|
|
10373
10777
|
} else {
|
|
10374
10778
|
throw E_UNAUTHORIZED;
|
|
10375
10779
|
}
|
|
@@ -12011,14 +12415,16 @@ const MediaLightbox = ({
|
|
|
12011
12415
|
item,
|
|
12012
12416
|
onClose
|
|
12013
12417
|
}) => {
|
|
12418
|
+
useEffect(() => {
|
|
12419
|
+
if (!item)
|
|
12420
|
+
return;
|
|
12421
|
+
captureEvent(MediaUsageDashboardPreviewOpenedEvent);
|
|
12422
|
+
}, [item]);
|
|
12014
12423
|
if (!item)
|
|
12015
12424
|
return null;
|
|
12016
12425
|
const usageCount = item.usedIn.length;
|
|
12017
12426
|
const mediaSrc = item.media.src;
|
|
12018
12427
|
const directory = item.media.directory || "/";
|
|
12019
|
-
useEffect(() => {
|
|
12020
|
-
captureEvent(MediaUsageDashboardPreviewOpenedEvent);
|
|
12021
|
-
}, []);
|
|
12022
12428
|
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(
|
|
12023
12429
|
VideoLightboxContent,
|
|
12024
12430
|
{
|
|
@@ -12780,7 +13186,7 @@ const NavProvider = ({
|
|
|
12780
13186
|
const name = "tinacms";
|
|
12781
13187
|
const type = "module";
|
|
12782
13188
|
const typings = "dist/index.d.ts";
|
|
12783
|
-
const version$1 = "3.
|
|
13189
|
+
const version$1 = "3.9.0";
|
|
12784
13190
|
const main = "dist/index.js";
|
|
12785
13191
|
const module = "./dist/index.js";
|
|
12786
13192
|
const exports = {
|
|
@@ -13511,7 +13917,7 @@ function BreadcrumbEllipsis({
|
|
|
13511
13917
|
);
|
|
13512
13918
|
}
|
|
13513
13919
|
const getPaddingClass = (depth) => `${1.5 + depth * 1.35}rem`;
|
|
13514
|
-
const collectAllDocumentItems = (
|
|
13920
|
+
const collectAllDocumentItems = (items, isGlobalFn) => {
|
|
13515
13921
|
const allItems = [];
|
|
13516
13922
|
const processItem = (item, isFromSubItems = false) => {
|
|
13517
13923
|
if (item.type === "document") {
|
|
@@ -13526,13 +13932,13 @@ const collectAllDocumentItems = (items2, isGlobalFn) => {
|
|
|
13526
13932
|
}
|
|
13527
13933
|
}
|
|
13528
13934
|
};
|
|
13529
|
-
|
|
13935
|
+
items.forEach((item) => processItem(item, false));
|
|
13530
13936
|
return allItems;
|
|
13531
13937
|
};
|
|
13532
|
-
const buildTreeFromPaths = (
|
|
13938
|
+
const buildTreeFromPaths = (items) => {
|
|
13533
13939
|
const root = [];
|
|
13534
13940
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
13535
|
-
|
|
13941
|
+
items.forEach((item) => {
|
|
13536
13942
|
const parts = item.formId.split("/").filter(Boolean);
|
|
13537
13943
|
let currentLevel = root;
|
|
13538
13944
|
let currentPath = "";
|
|
@@ -15369,23 +15775,6 @@ const BranchPreviewButton = (props) => {
|
|
|
15369
15775
|
/* @__PURE__ */ React.createElement(BiLinkExternal, { className: "h-5 w-auto" })
|
|
15370
15776
|
);
|
|
15371
15777
|
};
|
|
15372
|
-
const EDITORIAL_WORKFLOW_STATUS = {
|
|
15373
|
-
QUEUED: "queued",
|
|
15374
|
-
PROCESSING: "processing",
|
|
15375
|
-
SETTING_UP: "setting_up",
|
|
15376
|
-
CREATING_BRANCH: "creating_branch",
|
|
15377
|
-
INDEXING: "indexing",
|
|
15378
|
-
CONTENT_GENERATION: "content_generation",
|
|
15379
|
-
CREATING_PR: "creating_pr",
|
|
15380
|
-
COMPLETE: "complete",
|
|
15381
|
-
ERROR: "error",
|
|
15382
|
-
TIMEOUT: "timeout"
|
|
15383
|
-
};
|
|
15384
|
-
const EDITORIAL_WORKFLOW_ERROR = {
|
|
15385
|
-
BRANCH_EXISTS: "BRANCH_EXISTS",
|
|
15386
|
-
BRANCH_HIERARCHY_CONFLICT: "BRANCH_HIERARCHY_CONFLICT",
|
|
15387
|
-
VALIDATION_FAILED: "VALIDATION_FAILED"
|
|
15388
|
-
};
|
|
15389
15778
|
const CREATE_DOCUMENT_GQL = `#graphql
|
|
15390
15779
|
mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
|
|
15391
15780
|
createDocument(
|
|
@@ -15743,6 +16132,18 @@ const pathRelativeToCollection = (collectionPath, fullPath) => {
|
|
|
15743
16132
|
`Path ${fullPath} not within collection path ${collectionPath}`
|
|
15744
16133
|
);
|
|
15745
16134
|
};
|
|
16135
|
+
const getEditorialWorkflowMutation = (crudType) => {
|
|
16136
|
+
if (crudType === "create") {
|
|
16137
|
+
return CREATE_DOCUMENT_GQL;
|
|
16138
|
+
}
|
|
16139
|
+
if (crudType === "delete") {
|
|
16140
|
+
return DELETE_DOCUMENT_GQL;
|
|
16141
|
+
}
|
|
16142
|
+
if (crudType !== "view") {
|
|
16143
|
+
return UPDATE_DOCUMENT_GQL;
|
|
16144
|
+
}
|
|
16145
|
+
return "";
|
|
16146
|
+
};
|
|
15746
16147
|
const WORKFLOW_STEPS = [
|
|
15747
16148
|
{ id: 1, name: "Creating branch", description: "Setting up workspace" },
|
|
15748
16149
|
{ id: 2, name: "Updating branch", description: "Syncing content to branch" },
|
|
@@ -15753,6 +16154,33 @@ const formatTime = (seconds) => {
|
|
|
15753
16154
|
const secs = seconds % 60;
|
|
15754
16155
|
return `${mins}:${secs.toString().padStart(2, "0")}`;
|
|
15755
16156
|
};
|
|
16157
|
+
const getEditorialWorkflowErrorMessage = (e) => {
|
|
16158
|
+
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 🦙";
|
|
16159
|
+
const err = e;
|
|
16160
|
+
if (err.errorCode) {
|
|
16161
|
+
switch (err.errorCode) {
|
|
16162
|
+
case EDITORIAL_WORKFLOW_ERROR.BRANCH_EXISTS:
|
|
16163
|
+
errMessage = "A branch with this name already exists";
|
|
16164
|
+
break;
|
|
16165
|
+
case EDITORIAL_WORKFLOW_ERROR.BRANCH_HIERARCHY_CONFLICT:
|
|
16166
|
+
errMessage = err.message || "Branch name conflicts with an existing branch";
|
|
16167
|
+
break;
|
|
16168
|
+
case EDITORIAL_WORKFLOW_ERROR.VALIDATION_FAILED:
|
|
16169
|
+
errMessage = err.message || "Invalid branch name";
|
|
16170
|
+
break;
|
|
16171
|
+
default:
|
|
16172
|
+
errMessage = err.message || errMessage;
|
|
16173
|
+
break;
|
|
16174
|
+
}
|
|
16175
|
+
} else if (err.message) {
|
|
16176
|
+
if (err.message.toLowerCase().includes("already exists")) {
|
|
16177
|
+
errMessage = "A branch with this name already exists";
|
|
16178
|
+
} else if (err.message.toLowerCase().includes("conflict")) {
|
|
16179
|
+
errMessage = err.message;
|
|
16180
|
+
}
|
|
16181
|
+
}
|
|
16182
|
+
return errMessage;
|
|
16183
|
+
};
|
|
15756
16184
|
function useEditorialWorkflow() {
|
|
15757
16185
|
const cms = useCMS$1();
|
|
15758
16186
|
const tinaApi = cms.api.tina;
|
|
@@ -15786,20 +16214,30 @@ function useEditorialWorkflow() {
|
|
|
15786
16214
|
path,
|
|
15787
16215
|
values,
|
|
15788
16216
|
crudType,
|
|
15789
|
-
tinaForm
|
|
16217
|
+
tinaForm,
|
|
16218
|
+
signal
|
|
15790
16219
|
}) => {
|
|
15791
16220
|
var _a;
|
|
15792
16221
|
try {
|
|
16222
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
16223
|
+
return false;
|
|
16224
|
+
const targetBranchExists = await checkTargetBranchExists(
|
|
16225
|
+
tinaApi,
|
|
16226
|
+
branchName,
|
|
16227
|
+
"executeEditorialWorkflow",
|
|
16228
|
+
signal
|
|
16229
|
+
);
|
|
16230
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
16231
|
+
return false;
|
|
16232
|
+
if (targetBranchExists) {
|
|
16233
|
+
setErrorMessage(TARGET_BRANCH_EXISTS_ERROR);
|
|
16234
|
+
setIsExecuting(false);
|
|
16235
|
+
setCurrentStep(0);
|
|
16236
|
+
return false;
|
|
16237
|
+
}
|
|
15793
16238
|
setIsExecuting(true);
|
|
15794
16239
|
setCurrentStep(1);
|
|
15795
|
-
|
|
15796
|
-
if (crudType === "create") {
|
|
15797
|
-
graphql2 = CREATE_DOCUMENT_GQL;
|
|
15798
|
-
} else if (crudType === "delete") {
|
|
15799
|
-
graphql2 = DELETE_DOCUMENT_GQL;
|
|
15800
|
-
} else if (crudType !== "view") {
|
|
15801
|
-
graphql2 = UPDATE_DOCUMENT_GQL;
|
|
15802
|
-
}
|
|
16240
|
+
const graphql2 = getEditorialWorkflowMutation(crudType);
|
|
15803
16241
|
const collection = tinaApi.schema.getCollectionByFullPath(path);
|
|
15804
16242
|
let submittedValues = values;
|
|
15805
16243
|
if ((_a = collection == null ? void 0 : collection.ui) == null ? void 0 : _a.beforeSubmit) {
|
|
@@ -15820,7 +16258,7 @@ function useEditorialWorkflow() {
|
|
|
15820
16258
|
const result = await tinaApi.executeEditorialWorkflow({
|
|
15821
16259
|
branchName,
|
|
15822
16260
|
baseBranch,
|
|
15823
|
-
prTitle:
|
|
16261
|
+
prTitle: getEditorialWorkflowPrTitle(branchName),
|
|
15824
16262
|
graphQLContentOp: {
|
|
15825
16263
|
query: graphql2,
|
|
15826
16264
|
variables: {
|
|
@@ -15869,30 +16307,7 @@ function useEditorialWorkflow() {
|
|
|
15869
16307
|
return true;
|
|
15870
16308
|
} catch (e) {
|
|
15871
16309
|
console.error(e);
|
|
15872
|
-
|
|
15873
|
-
const err = e;
|
|
15874
|
-
if (err.errorCode) {
|
|
15875
|
-
switch (err.errorCode) {
|
|
15876
|
-
case EDITORIAL_WORKFLOW_ERROR.BRANCH_EXISTS:
|
|
15877
|
-
errMessage = "A branch with this name already exists";
|
|
15878
|
-
break;
|
|
15879
|
-
case EDITORIAL_WORKFLOW_ERROR.BRANCH_HIERARCHY_CONFLICT:
|
|
15880
|
-
errMessage = err.message || "Branch name conflicts with an existing branch";
|
|
15881
|
-
break;
|
|
15882
|
-
case EDITORIAL_WORKFLOW_ERROR.VALIDATION_FAILED:
|
|
15883
|
-
errMessage = err.message || "Invalid branch name";
|
|
15884
|
-
break;
|
|
15885
|
-
default:
|
|
15886
|
-
errMessage = err.message || errMessage;
|
|
15887
|
-
break;
|
|
15888
|
-
}
|
|
15889
|
-
} else if (err.message) {
|
|
15890
|
-
if (err.message.toLowerCase().includes("already exists")) {
|
|
15891
|
-
errMessage = "A branch with this name already exists";
|
|
15892
|
-
} else if (err.message.toLowerCase().includes("conflict")) {
|
|
15893
|
-
errMessage = err.message;
|
|
15894
|
-
}
|
|
15895
|
-
}
|
|
16310
|
+
const errMessage = getEditorialWorkflowErrorMessage(e);
|
|
15896
16311
|
setErrorMessage(errMessage);
|
|
15897
16312
|
setIsExecuting(false);
|
|
15898
16313
|
setCurrentStep(0);
|
|
@@ -15980,6 +16395,18 @@ const WorkflowProgressIndicator = ({
|
|
|
15980
16395
|
"Learn more about Editorial Workflow"
|
|
15981
16396
|
));
|
|
15982
16397
|
};
|
|
16398
|
+
const EditorialWorkflowProgressModal = ({
|
|
16399
|
+
title,
|
|
16400
|
+
currentStep,
|
|
16401
|
+
elapsedTime
|
|
16402
|
+
}) => /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, null, title), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement(
|
|
16403
|
+
WorkflowProgressIndicator,
|
|
16404
|
+
{
|
|
16405
|
+
currentStep,
|
|
16406
|
+
isExecuting: true,
|
|
16407
|
+
elapsedTime
|
|
16408
|
+
}
|
|
16409
|
+
))));
|
|
15983
16410
|
const formatDefaultBranchName = (filePath, crudType) => {
|
|
15984
16411
|
let result = filePath;
|
|
15985
16412
|
const contentPrefix = "content/";
|
|
@@ -16011,6 +16438,7 @@ const CreateBranchModal = ({
|
|
|
16011
16438
|
formatDefaultBranchName(path, crudType)
|
|
16012
16439
|
);
|
|
16013
16440
|
const [isBranchGuardChecking, setIsBranchGuardChecking] = React.useState(false);
|
|
16441
|
+
const branchGuardAbortRef = React.useRef(null);
|
|
16014
16442
|
const {
|
|
16015
16443
|
isExecuting,
|
|
16016
16444
|
errorMessage,
|
|
@@ -16019,27 +16447,35 @@ const CreateBranchModal = ({
|
|
|
16019
16447
|
executeWorkflow,
|
|
16020
16448
|
reset
|
|
16021
16449
|
} = useEditorialWorkflow();
|
|
16450
|
+
const abortBranchGuard = React.useCallback(() => {
|
|
16451
|
+
var _a;
|
|
16452
|
+
(_a = branchGuardAbortRef.current) == null ? void 0 : _a.abort();
|
|
16453
|
+
branchGuardAbortRef.current = null;
|
|
16454
|
+
setIsBranchGuardChecking(false);
|
|
16455
|
+
}, []);
|
|
16456
|
+
React.useEffect(() => {
|
|
16457
|
+
return () => {
|
|
16458
|
+
var _a;
|
|
16459
|
+
(_a = branchGuardAbortRef.current) == null ? void 0 : _a.abort();
|
|
16460
|
+
};
|
|
16461
|
+
}, []);
|
|
16022
16462
|
const executeEditorialWorkflow = async () => {
|
|
16463
|
+
abortBranchGuard();
|
|
16464
|
+
const abortController = new AbortController();
|
|
16465
|
+
branchGuardAbortRef.current = abortController;
|
|
16023
16466
|
setIsBranchGuardChecking(true);
|
|
16024
16467
|
const baseBranch = decodeURIComponent(tinaApi.branch);
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
baseBranchExists = await tinaApi.branchExists(baseBranch);
|
|
16032
|
-
} catch (err) {
|
|
16033
|
-
console.error(
|
|
16034
|
-
"[tina:branch-guard] executeEditorialWorkflow: branchExists threw, failing open:",
|
|
16035
|
-
err
|
|
16036
|
-
);
|
|
16037
|
-
}
|
|
16038
|
-
console.debug(
|
|
16039
|
-
"[tina:branch-guard] executeEditorialWorkflow: base branch exists?",
|
|
16040
|
-
baseBranchExists
|
|
16468
|
+
const targetBranch = `tina/${newBranchName}`;
|
|
16469
|
+
const baseBranchExists = await checkBaseBranchExists(
|
|
16470
|
+
tinaApi,
|
|
16471
|
+
baseBranch,
|
|
16472
|
+
"executeEditorialWorkflow",
|
|
16473
|
+
abortController.signal
|
|
16041
16474
|
);
|
|
16475
|
+
if (abortController.signal.aborted)
|
|
16476
|
+
return;
|
|
16042
16477
|
if (!baseBranchExists) {
|
|
16478
|
+
abortBranchGuard();
|
|
16043
16479
|
console.debug(
|
|
16044
16480
|
"[tina:branch-guard] executeEditorialWorkflow: base branch deleted — handing off"
|
|
16045
16481
|
);
|
|
@@ -16048,52 +16484,84 @@ const CreateBranchModal = ({
|
|
|
16048
16484
|
}
|
|
16049
16485
|
setIsBranchGuardChecking(false);
|
|
16050
16486
|
const success = await executeWorkflow({
|
|
16051
|
-
branchName:
|
|
16487
|
+
branchName: targetBranch,
|
|
16052
16488
|
baseBranch,
|
|
16053
16489
|
path,
|
|
16054
16490
|
values,
|
|
16055
16491
|
crudType,
|
|
16056
|
-
tinaForm
|
|
16492
|
+
tinaForm,
|
|
16493
|
+
signal: abortController.signal
|
|
16057
16494
|
});
|
|
16495
|
+
if (branchGuardAbortRef.current === abortController) {
|
|
16496
|
+
branchGuardAbortRef.current = null;
|
|
16497
|
+
}
|
|
16058
16498
|
if (success) {
|
|
16059
16499
|
close2();
|
|
16060
16500
|
}
|
|
16061
16501
|
};
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
|
|
16074
|
-
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
));
|
|
16502
|
+
if (isExecuting) {
|
|
16503
|
+
return /* @__PURE__ */ React.createElement(
|
|
16504
|
+
EditorialWorkflowProgressModal,
|
|
16505
|
+
{
|
|
16506
|
+
title: "Save changes to new branch",
|
|
16507
|
+
currentStep,
|
|
16508
|
+
elapsedTime
|
|
16509
|
+
}
|
|
16510
|
+
);
|
|
16511
|
+
}
|
|
16512
|
+
return /* @__PURE__ */ React.createElement(
|
|
16513
|
+
CreateBranchPromptModal,
|
|
16514
|
+
{
|
|
16515
|
+
branchName: newBranchName,
|
|
16516
|
+
close: () => {
|
|
16517
|
+
abortBranchGuard();
|
|
16518
|
+
close2();
|
|
16519
|
+
},
|
|
16520
|
+
errorMessage,
|
|
16521
|
+
disabled: newBranchName === "" || isBranchGuardChecking,
|
|
16522
|
+
onBranchNameChange: (value) => {
|
|
16523
|
+
abortBranchGuard();
|
|
16524
|
+
reset();
|
|
16525
|
+
setNewBranchName(value);
|
|
16526
|
+
},
|
|
16527
|
+
onCreateBranch: executeEditorialWorkflow,
|
|
16528
|
+
onSaveToProtectedBranch: () => {
|
|
16529
|
+
abortBranchGuard();
|
|
16530
|
+
close2();
|
|
16531
|
+
safeSubmit();
|
|
16532
|
+
}
|
|
16094
16533
|
}
|
|
16095
|
-
|
|
16096
|
-
|
|
16534
|
+
);
|
|
16535
|
+
};
|
|
16536
|
+
const CreateBranchPromptModal = ({
|
|
16537
|
+
branchName,
|
|
16538
|
+
close: close2,
|
|
16539
|
+
disabled,
|
|
16540
|
+
errorMessage,
|
|
16541
|
+
onBranchNameChange,
|
|
16542
|
+
onCreateBranch,
|
|
16543
|
+
onSaveToProtectedBranch
|
|
16544
|
+
}) => {
|
|
16545
|
+
return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: close2 }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between w-full" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, "Save changes to new branch"))), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__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(
|
|
16546
|
+
"a",
|
|
16547
|
+
{
|
|
16548
|
+
className: "underline text-tina-orange-dark font-medium",
|
|
16549
|
+
href: "https://tina.io/docs/r/editorial-workflow",
|
|
16550
|
+
target: "_blank"
|
|
16551
|
+
},
|
|
16552
|
+
"Editorial Workflow"
|
|
16553
|
+
), "."), /* @__PURE__ */ React.createElement(
|
|
16554
|
+
PrefixedTextField,
|
|
16555
|
+
{
|
|
16556
|
+
name: "new-branch-name",
|
|
16557
|
+
label: "Branch Name",
|
|
16558
|
+
placeholder: "e.g. {{PAGE-NAME}}-updates",
|
|
16559
|
+
value: branchName,
|
|
16560
|
+
onChange: (e) => {
|
|
16561
|
+
onBranchNameChange(e.target.value);
|
|
16562
|
+
}
|
|
16563
|
+
}
|
|
16564
|
+
))), /* @__PURE__ */ React.createElement(ModalActions, { align: "end" }, /* @__PURE__ */ React.createElement(
|
|
16097
16565
|
Button$2,
|
|
16098
16566
|
{
|
|
16099
16567
|
variant: "secondary",
|
|
@@ -16107,26 +16575,17 @@ const CreateBranchModal = ({
|
|
|
16107
16575
|
variant: "primary",
|
|
16108
16576
|
align: "start",
|
|
16109
16577
|
className: "w-full sm:w-auto",
|
|
16110
|
-
disabled
|
|
16111
|
-
onMainAction:
|
|
16578
|
+
disabled,
|
|
16579
|
+
onMainAction: onCreateBranch,
|
|
16112
16580
|
items: [
|
|
16113
16581
|
{
|
|
16114
16582
|
label: "Save to Protected Branch",
|
|
16115
|
-
onClick:
|
|
16116
|
-
close2();
|
|
16117
|
-
safeSubmit();
|
|
16118
|
-
},
|
|
16583
|
+
onClick: onSaveToProtectedBranch,
|
|
16119
16584
|
icon: /* @__PURE__ */ React.createElement(TriangleAlert, { className: "w-4 h-4" })
|
|
16120
16585
|
}
|
|
16121
16586
|
]
|
|
16122
16587
|
},
|
|
16123
|
-
/* @__PURE__ */ React.createElement(
|
|
16124
|
-
GitBranchIcon,
|
|
16125
|
-
{
|
|
16126
|
-
className: "w-4 h-4 mr-1",
|
|
16127
|
-
style: { fill: "none" }
|
|
16128
|
-
}
|
|
16129
|
-
),
|
|
16588
|
+
/* @__PURE__ */ React.createElement(GitBranchIcon, { className: "w-4 h-4 mr-1", style: { fill: "none" } }),
|
|
16130
16589
|
"Save to a new branch"
|
|
16131
16590
|
))));
|
|
16132
16591
|
};
|
|
@@ -17004,43 +17463,15 @@ const formatList = (editor, elementType) => {
|
|
|
17004
17463
|
})
|
|
17005
17464
|
);
|
|
17006
17465
|
};
|
|
17007
|
-
const
|
|
17008
|
-
{
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
}
|
|
17014
|
-
|
|
17015
|
-
|
|
17016
|
-
type: HEADING_KEYS.h2,
|
|
17017
|
-
match: "## ",
|
|
17018
|
-
preFormat
|
|
17019
|
-
},
|
|
17020
|
-
{
|
|
17021
|
-
mode: "block",
|
|
17022
|
-
type: HEADING_KEYS.h3,
|
|
17023
|
-
match: "### ",
|
|
17024
|
-
preFormat
|
|
17025
|
-
},
|
|
17026
|
-
{
|
|
17027
|
-
mode: "block",
|
|
17028
|
-
type: HEADING_KEYS.h4,
|
|
17029
|
-
match: "#### ",
|
|
17030
|
-
preFormat
|
|
17031
|
-
},
|
|
17032
|
-
{
|
|
17033
|
-
mode: "block",
|
|
17034
|
-
type: HEADING_KEYS.h5,
|
|
17035
|
-
match: "##### ",
|
|
17036
|
-
preFormat
|
|
17037
|
-
},
|
|
17038
|
-
{
|
|
17039
|
-
mode: "block",
|
|
17040
|
-
type: HEADING_KEYS.h6,
|
|
17041
|
-
match: "###### ",
|
|
17042
|
-
preFormat
|
|
17043
|
-
},
|
|
17466
|
+
const headingAutoformatByLevel = {
|
|
17467
|
+
h1: { mode: "block", type: HEADING_KEYS.h1, match: "# ", preFormat },
|
|
17468
|
+
h2: { mode: "block", type: HEADING_KEYS.h2, match: "## ", preFormat },
|
|
17469
|
+
h3: { mode: "block", type: HEADING_KEYS.h3, match: "### ", preFormat },
|
|
17470
|
+
h4: { mode: "block", type: HEADING_KEYS.h4, match: "#### ", preFormat },
|
|
17471
|
+
h5: { mode: "block", type: HEADING_KEYS.h5, match: "##### ", preFormat },
|
|
17472
|
+
h6: { mode: "block", type: HEADING_KEYS.h6, match: "###### ", preFormat }
|
|
17473
|
+
};
|
|
17474
|
+
const nonHeadingAutoformatBlocks = [
|
|
17044
17475
|
{
|
|
17045
17476
|
mode: "block",
|
|
17046
17477
|
type: BlockquotePlugin.key,
|
|
@@ -17072,6 +17503,16 @@ const autoformatBlocks = [
|
|
|
17072
17503
|
}
|
|
17073
17504
|
}
|
|
17074
17505
|
];
|
|
17506
|
+
const getAutoformatBlocks = (headingLevels = ALL_HEADING_LEVELS) => [
|
|
17507
|
+
// Normalize so a pure-JS schema passing e.g. `['h7']` doesn't push an
|
|
17508
|
+
// `undefined` rule into the autoformat config. The toolbar context
|
|
17509
|
+
// applies the same filter, keeping both surfaces consistent.
|
|
17510
|
+
...normalizeHeadingLevels(headingLevels).map(
|
|
17511
|
+
(level) => headingAutoformatByLevel[level]
|
|
17512
|
+
),
|
|
17513
|
+
...nonHeadingAutoformatBlocks
|
|
17514
|
+
];
|
|
17515
|
+
const autoformatBlocks = getAutoformatBlocks();
|
|
17075
17516
|
const autoformatLists = [
|
|
17076
17517
|
{
|
|
17077
17518
|
mode: "block",
|
|
@@ -17449,70 +17890,36 @@ const HEADING_ICON_ONLY = 58;
|
|
|
17449
17890
|
const EMBED_ICON_WIDTH = 78;
|
|
17450
17891
|
const CONTAINER_MD_BREAKPOINT = 448;
|
|
17451
17892
|
const HEADING_LABEL = "Headings";
|
|
17452
|
-
const
|
|
17453
|
-
|
|
17454
|
-
)
|
|
17455
|
-
|
|
17456
|
-
|
|
17457
|
-
|
|
17458
|
-
|
|
17459
|
-
|
|
17460
|
-
|
|
17461
|
-
|
|
17462
|
-
|
|
17463
|
-
|
|
17464
|
-
|
|
17465
|
-
|
|
17466
|
-
|
|
17467
|
-
}
|
|
17468
|
-
|
|
17893
|
+
const buildByLevel = (make) => ({
|
|
17894
|
+
h1: make("h1"),
|
|
17895
|
+
h2: make("h2"),
|
|
17896
|
+
h3: make("h3"),
|
|
17897
|
+
h4: make("h4"),
|
|
17898
|
+
h5: make("h5"),
|
|
17899
|
+
h6: make("h6")
|
|
17900
|
+
});
|
|
17901
|
+
const headingItemsByLevel = buildByLevel((level) => {
|
|
17902
|
+
const depth = level.slice(1);
|
|
17903
|
+
return {
|
|
17904
|
+
description: `Heading ${depth}`,
|
|
17905
|
+
icon: Icons[level],
|
|
17906
|
+
label: `Heading ${depth}`,
|
|
17907
|
+
value: level
|
|
17908
|
+
};
|
|
17909
|
+
});
|
|
17910
|
+
const paragraphItem = {
|
|
17911
|
+
description: "Paragraph",
|
|
17912
|
+
icon: Icons.paragraph,
|
|
17913
|
+
label: "Paragraph",
|
|
17914
|
+
value: ParagraphPlugin.key
|
|
17469
17915
|
};
|
|
17470
|
-
const
|
|
17471
|
-
{
|
|
17472
|
-
description: "Paragraph",
|
|
17473
|
-
icon: Icons.heading,
|
|
17474
|
-
label: "Paragraph",
|
|
17475
|
-
value: ParagraphPlugin.key
|
|
17476
|
-
},
|
|
17477
|
-
{
|
|
17478
|
-
description: "Heading 1",
|
|
17479
|
-
icon: Icons.h1,
|
|
17480
|
-
label: "Heading 1",
|
|
17481
|
-
value: HEADING_KEYS.h1
|
|
17482
|
-
},
|
|
17483
|
-
{
|
|
17484
|
-
description: "Heading 2",
|
|
17485
|
-
icon: Icons.h2,
|
|
17486
|
-
label: "Heading 2",
|
|
17487
|
-
value: HEADING_KEYS.h2
|
|
17488
|
-
},
|
|
17489
|
-
{
|
|
17490
|
-
description: "Heading 3",
|
|
17491
|
-
icon: Icons.h3,
|
|
17492
|
-
label: "Heading 3",
|
|
17493
|
-
value: HEADING_KEYS.h3
|
|
17494
|
-
},
|
|
17495
|
-
{
|
|
17496
|
-
description: "Heading 4",
|
|
17497
|
-
icon: Icons.h4,
|
|
17498
|
-
label: "Heading 4",
|
|
17499
|
-
value: HEADING_KEYS.h4
|
|
17500
|
-
},
|
|
17501
|
-
{
|
|
17502
|
-
description: "Heading 5",
|
|
17503
|
-
icon: Icons.h5,
|
|
17504
|
-
label: "Heading 5",
|
|
17505
|
-
value: HEADING_KEYS.h5
|
|
17506
|
-
},
|
|
17507
|
-
{
|
|
17508
|
-
description: "Heading 6",
|
|
17509
|
-
icon: Icons.h6,
|
|
17510
|
-
label: "Heading 6",
|
|
17511
|
-
value: HEADING_KEYS.h6
|
|
17512
|
-
}
|
|
17513
|
-
];
|
|
17514
|
-
const defaultItem$1 = items$1.find((item) => item.value === ParagraphPlugin.key) || items$1[0];
|
|
17916
|
+
const getHeadingItem = (value) => isHeadingLevel(value) ? headingItemsByLevel[value] : void 0;
|
|
17515
17917
|
function HeadingsMenu(props) {
|
|
17918
|
+
const { headingLevels } = useToolbarContext();
|
|
17919
|
+
const items = [
|
|
17920
|
+
paragraphItem,
|
|
17921
|
+
...headingLevels.map((level) => headingItemsByLevel[level])
|
|
17922
|
+
];
|
|
17516
17923
|
const value = useEditorSelector((editor2) => {
|
|
17517
17924
|
let initialNodeType = ParagraphPlugin.key;
|
|
17518
17925
|
let allNodesMatchInitialNodeType = false;
|
|
@@ -17534,7 +17941,7 @@ function HeadingsMenu(props) {
|
|
|
17534
17941
|
const editorState = useEditorState();
|
|
17535
17942
|
const openState = useOpenState();
|
|
17536
17943
|
const userInTable = helpers.isNodeActive(editorState, TablePlugin.key);
|
|
17537
|
-
const selectedItem =
|
|
17944
|
+
const selectedItem = getHeadingItem(value) ?? paragraphItem;
|
|
17538
17945
|
const { icon: SelectedItemIcon, label: selectedItemLabel } = selectedItem;
|
|
17539
17946
|
return /* @__PURE__ */ React__default.createElement("div", { className: "rounded-md" }, /* @__PURE__ */ React__default.createElement(DropdownMenu$1, { modal: false, ...openState, ...props }, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement(
|
|
17540
17947
|
ToolbarButton,
|
|
@@ -17563,7 +17970,7 @@ function HeadingsMenu(props) {
|
|
|
17563
17970
|
},
|
|
17564
17971
|
value
|
|
17565
17972
|
},
|
|
17566
|
-
items
|
|
17973
|
+
items.filter((item) => {
|
|
17567
17974
|
if (userInTable) {
|
|
17568
17975
|
return !unsupportedItemsInTable.has(item.label);
|
|
17569
17976
|
}
|
|
@@ -18239,27 +18646,27 @@ function FixedToolbarButtons() {
|
|
|
18239
18646
|
const [itemsShown, setItemsShown] = React__default.useState(11);
|
|
18240
18647
|
const { overrides, templates } = useToolbarContext();
|
|
18241
18648
|
const showEmbedButton = templates.length > 0;
|
|
18242
|
-
let
|
|
18649
|
+
let items = [];
|
|
18243
18650
|
if (Array.isArray(overrides)) {
|
|
18244
|
-
|
|
18651
|
+
items = overrides === void 0 ? Object.values(toolbarItems) : overrides.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
|
|
18245
18652
|
} else {
|
|
18246
|
-
|
|
18653
|
+
items = (overrides == null ? void 0 : overrides.toolbar) === void 0 ? Object.values(toolbarItems) : overrides.toolbar.map((item) => toolbarItems[item]).filter((item) => item !== void 0);
|
|
18247
18654
|
}
|
|
18248
18655
|
if (!showEmbedButton) {
|
|
18249
|
-
|
|
18656
|
+
items = items.filter((item) => item.label !== toolbarItems.embed.label);
|
|
18250
18657
|
}
|
|
18251
18658
|
const editorState = useEditorState();
|
|
18252
18659
|
const userInTable = helpers.isNodeActive(editorState, TablePlugin);
|
|
18253
18660
|
const userInCodeBlock = helpers.isNodeActive(editorState, CodeBlockPlugin);
|
|
18254
18661
|
useResize(toolbarRef, (entry) => {
|
|
18255
18662
|
const width = entry.target.getBoundingClientRect().width - 8;
|
|
18256
|
-
const headingButton =
|
|
18663
|
+
const headingButton = items.find((item) => item.label === HEADING_LABEL);
|
|
18257
18664
|
const headingWidth = headingButton ? (
|
|
18258
18665
|
//some discrepancy here between the md breakpoint here and in practice, but it works
|
|
18259
18666
|
headingButton.width(width > CONTAINER_MD_BREAKPOINT - 9)
|
|
18260
18667
|
) : 0;
|
|
18261
18668
|
const availableWidth = width - headingWidth;
|
|
18262
|
-
const { itemFitCount } =
|
|
18669
|
+
const { itemFitCount } = items.reduce(
|
|
18263
18670
|
(acc, item) => {
|
|
18264
18671
|
if (item.label !== HEADING_LABEL && acc.totalItemsWidth + item.width() <= availableWidth) {
|
|
18265
18672
|
return {
|
|
@@ -18291,7 +18698,7 @@ function FixedToolbarButtons() {
|
|
|
18291
18698
|
transform: "translateX(calc(-1px))"
|
|
18292
18699
|
}
|
|
18293
18700
|
},
|
|
18294
|
-
/* @__PURE__ */ React__default.createElement(React__default.Fragment, null,
|
|
18701
|
+
/* @__PURE__ */ React__default.createElement(React__default.Fragment, null, items.slice(0, items.length > itemsShown ? itemsShown - 1 : itemsShown).map((item) => /* @__PURE__ */ React__default.createElement(
|
|
18295
18702
|
"div",
|
|
18296
18703
|
{
|
|
18297
18704
|
className: cn(
|
|
@@ -18301,7 +18708,7 @@ function FixedToolbarButtons() {
|
|
|
18301
18708
|
key: item.label
|
|
18302
18709
|
},
|
|
18303
18710
|
item.Component
|
|
18304
|
-
)),
|
|
18711
|
+
)), items.length > itemsShown && /* @__PURE__ */ React__default.createElement("div", { className: "w-fit ml-auto" }, /* @__PURE__ */ React__default.createElement(OverflowMenu, null, items.slice(itemsShown - 1).flatMap((c2) => /* @__PURE__ */ React__default.createElement(
|
|
18305
18712
|
"div",
|
|
18306
18713
|
{
|
|
18307
18714
|
className: cn(
|
|
@@ -18789,52 +19196,12 @@ const FloatingToolbar = withRef(({ children, state, ...props }, propRef) => {
|
|
|
18789
19196
|
children
|
|
18790
19197
|
));
|
|
18791
19198
|
});
|
|
18792
|
-
const items = [
|
|
18793
|
-
{
|
|
18794
|
-
description: "Paragraph",
|
|
18795
|
-
icon: Icons.paragraph,
|
|
18796
|
-
label: "Paragraph",
|
|
18797
|
-
value: ParagraphPlugin.key
|
|
18798
|
-
},
|
|
18799
|
-
{
|
|
18800
|
-
description: "Heading 1",
|
|
18801
|
-
icon: Icons.h1,
|
|
18802
|
-
label: "Heading 1",
|
|
18803
|
-
value: HEADING_KEYS.h1
|
|
18804
|
-
},
|
|
18805
|
-
{
|
|
18806
|
-
description: "Heading 2",
|
|
18807
|
-
icon: Icons.h2,
|
|
18808
|
-
label: "Heading 2",
|
|
18809
|
-
value: HEADING_KEYS.h2
|
|
18810
|
-
},
|
|
18811
|
-
{
|
|
18812
|
-
description: "Heading 3",
|
|
18813
|
-
icon: Icons.h3,
|
|
18814
|
-
label: "Heading 3",
|
|
18815
|
-
value: HEADING_KEYS.h3
|
|
18816
|
-
},
|
|
18817
|
-
{
|
|
18818
|
-
description: "Heading 4",
|
|
18819
|
-
icon: Icons.h4,
|
|
18820
|
-
label: "Heading 4",
|
|
18821
|
-
value: HEADING_KEYS.h4
|
|
18822
|
-
},
|
|
18823
|
-
{
|
|
18824
|
-
description: "Heading 5",
|
|
18825
|
-
icon: Icons.h5,
|
|
18826
|
-
label: "Heading 5",
|
|
18827
|
-
value: HEADING_KEYS.h5
|
|
18828
|
-
},
|
|
18829
|
-
{
|
|
18830
|
-
description: "Heading 6",
|
|
18831
|
-
icon: Icons.h6,
|
|
18832
|
-
label: "Heading 6",
|
|
18833
|
-
value: HEADING_KEYS.h6
|
|
18834
|
-
}
|
|
18835
|
-
];
|
|
18836
|
-
const defaultItem = items.find((item) => item.value === ParagraphPlugin.key);
|
|
18837
19199
|
function TurnIntoDropdownMenu(props) {
|
|
19200
|
+
const { headingLevels } = useToolbarContext();
|
|
19201
|
+
const items = [
|
|
19202
|
+
paragraphItem,
|
|
19203
|
+
...headingLevels.map((level) => headingItemsByLevel[level])
|
|
19204
|
+
];
|
|
18838
19205
|
const value = useEditorSelector((editor2) => {
|
|
18839
19206
|
let initialNodeType = ParagraphPlugin.key;
|
|
18840
19207
|
let allNodesMatchInitialNodeType = false;
|
|
@@ -18854,7 +19221,7 @@ function TurnIntoDropdownMenu(props) {
|
|
|
18854
19221
|
}, []);
|
|
18855
19222
|
const editor = useEditorRef();
|
|
18856
19223
|
const openState = useOpenState();
|
|
18857
|
-
const selectedItem =
|
|
19224
|
+
const selectedItem = getHeadingItem(value) ?? paragraphItem;
|
|
18858
19225
|
const { icon: SelectedItemIcon, label: selectedItemLabel } = selectedItem;
|
|
18859
19226
|
const editorState = useEditorState();
|
|
18860
19227
|
const userInTable = helpers.isNodeActive(editorState, TablePlugin.key);
|
|
@@ -61927,9 +62294,9 @@ function php(hljs) {
|
|
|
61927
62294
|
"static",
|
|
61928
62295
|
"stdClass"
|
|
61929
62296
|
];
|
|
61930
|
-
const dualCase = (
|
|
62297
|
+
const dualCase = (items) => {
|
|
61931
62298
|
const result = [];
|
|
61932
|
-
|
|
62299
|
+
items.forEach((item) => {
|
|
61933
62300
|
result.push(item);
|
|
61934
62301
|
if (item.toLowerCase() === item) {
|
|
61935
62302
|
result.push(item.toUpperCase());
|
|
@@ -61944,8 +62311,8 @@ function php(hljs) {
|
|
|
61944
62311
|
literal: dualCase(LITERALS2),
|
|
61945
62312
|
built_in: BUILT_INS2
|
|
61946
62313
|
};
|
|
61947
|
-
const normalizeKeywords = (
|
|
61948
|
-
return
|
|
62314
|
+
const normalizeKeywords = (items) => {
|
|
62315
|
+
return items.map((item) => {
|
|
61949
62316
|
return item.replace(/\|\d+$/, "");
|
|
61950
62317
|
});
|
|
61951
62318
|
};
|
|
@@ -69713,7 +70080,9 @@ const ClearHighlightOnEnterPlugin = createSlatePlugin({
|
|
|
69713
70080
|
}
|
|
69714
70081
|
}
|
|
69715
70082
|
}));
|
|
69716
|
-
const
|
|
70083
|
+
const createEditorPlugins = ({
|
|
70084
|
+
headingLevels
|
|
70085
|
+
} = {}) => [
|
|
69717
70086
|
createMdxBlockPlugin,
|
|
69718
70087
|
createMdxInlinePlugin,
|
|
69719
70088
|
createImgPlugin,
|
|
@@ -69737,9 +70106,9 @@ const editorPlugins = [
|
|
|
69737
70106
|
NodeIdPlugin,
|
|
69738
70107
|
TablePlugin,
|
|
69739
70108
|
SlashPlugin,
|
|
69740
|
-
//
|
|
70109
|
+
// Keeps a blank paragraph at the end of the editor so users can keep
|
|
70110
|
+
// typing after a heading, quote, or other terminal block.
|
|
69741
70111
|
TrailingBlockPlugin,
|
|
69742
|
-
//makes sure there's always a blank paragraph at the end of the editor.
|
|
69743
70112
|
createBreakPlugin,
|
|
69744
70113
|
FloatingToolbarPlugin,
|
|
69745
70114
|
AutoformatPlugin.configure({
|
|
@@ -69747,7 +70116,7 @@ const editorPlugins = [
|
|
|
69747
70116
|
enableUndoOnDelete: true,
|
|
69748
70117
|
rules: [
|
|
69749
70118
|
...autoformatMarks,
|
|
69750
|
-
...
|
|
70119
|
+
...getAutoformatBlocks(headingLevels),
|
|
69751
70120
|
...autoformatLists,
|
|
69752
70121
|
...autoformatSmartQuotes,
|
|
69753
70122
|
...autoformatPunctuation,
|
|
@@ -69757,6 +70126,7 @@ const editorPlugins = [
|
|
|
69757
70126
|
].map(
|
|
69758
70127
|
(rule) => ({
|
|
69759
70128
|
...rule,
|
|
70129
|
+
// Suppress autoformat inside code blocks so e.g. `# ` stays literal.
|
|
69760
70130
|
query: (editor) => !editor.api.some({
|
|
69761
70131
|
match: { type: editor.getType(CodeBlockPlugin) }
|
|
69762
70132
|
})
|
|
@@ -69764,29 +70134,21 @@ const editorPlugins = [
|
|
|
69764
70134
|
)
|
|
69765
70135
|
}
|
|
69766
70136
|
}),
|
|
69767
|
-
//
|
|
70137
|
+
// Lets users "break out" of a block (e.g. a heading) with Enter.
|
|
69768
70138
|
ExitBreakPlugin.configure({
|
|
69769
70139
|
options: {
|
|
69770
70140
|
rules: [
|
|
69771
|
-
{
|
|
69772
|
-
|
|
69773
|
-
},
|
|
69774
|
-
{
|
|
69775
|
-
hotkey: "mod+shift+enter",
|
|
69776
|
-
before: true
|
|
69777
|
-
},
|
|
70141
|
+
{ hotkey: "mod+enter" },
|
|
70142
|
+
{ hotkey: "mod+shift+enter", before: true },
|
|
69778
70143
|
{
|
|
69779
70144
|
hotkey: "enter",
|
|
69780
|
-
query: {
|
|
69781
|
-
start: true,
|
|
69782
|
-
end: true,
|
|
69783
|
-
allow: HEADING_LEVELS
|
|
69784
|
-
}
|
|
70145
|
+
query: { start: true, end: true, allow: HEADING_LEVELS }
|
|
69785
70146
|
}
|
|
69786
70147
|
]
|
|
69787
70148
|
}
|
|
69788
70149
|
}),
|
|
69789
|
-
//
|
|
70150
|
+
// Lets users turn a heading back into a paragraph by pressing Enter on
|
|
70151
|
+
// an empty heading or Backspace at the start of one.
|
|
69790
70152
|
ResetNodePlugin.configure({
|
|
69791
70153
|
options: {
|
|
69792
70154
|
rules: [
|
|
@@ -69798,9 +70160,7 @@ const editorPlugins = [
|
|
|
69798
70160
|
{
|
|
69799
70161
|
...resetBlockTypesCommonRule,
|
|
69800
70162
|
hotkey: "Backspace",
|
|
69801
|
-
predicate: (editor) => {
|
|
69802
|
-
return editor.api.isAt({ start: true });
|
|
69803
|
-
}
|
|
70163
|
+
predicate: (editor) => editor.api.isAt({ start: true })
|
|
69804
70164
|
},
|
|
69805
70165
|
{
|
|
69806
70166
|
...resetBlockTypesCodeBlockRule,
|
|
@@ -69812,10 +70172,11 @@ const editorPlugins = [
|
|
|
69812
70172
|
hotkey: "Backspace",
|
|
69813
70173
|
predicate: isSelectionAtCodeBlockStart
|
|
69814
70174
|
},
|
|
69815
|
-
//
|
|
69816
|
-
//
|
|
69817
|
-
//
|
|
69818
|
-
//
|
|
70175
|
+
// Plate's ListPlugin usually resets lists to paragraphs on Backspace
|
|
70176
|
+
// at the start of a list item, but when the list is the editor's
|
|
70177
|
+
// first node the default doesn't fully unwrap and we end up with an
|
|
70178
|
+
// invalid structure (e.g. <li> inside <p>). `onReset: unwrapList`
|
|
70179
|
+
// forces a clean reset in that case.
|
|
69819
70180
|
{
|
|
69820
70181
|
types: [BulletedListPlugin.key, NumberedListPlugin.key],
|
|
69821
70182
|
defaultType: ParagraphPlugin.key,
|
|
@@ -69832,21 +70193,19 @@ const editorPlugins = [
|
|
|
69832
70193
|
{ hotkey: "shift+enter" },
|
|
69833
70194
|
{
|
|
69834
70195
|
hotkey: "enter",
|
|
69835
|
-
query: {
|
|
69836
|
-
allow: [CodeBlockPlugin.key, BlockquotePlugin.key]
|
|
69837
|
-
}
|
|
70196
|
+
query: { allow: [CodeBlockPlugin.key, BlockquotePlugin.key] }
|
|
69838
70197
|
}
|
|
69839
70198
|
]
|
|
69840
70199
|
}
|
|
69841
70200
|
})
|
|
69842
70201
|
];
|
|
69843
70202
|
const RichEditor = ({ input, tinaForm, field }) => {
|
|
69844
|
-
var _a;
|
|
70203
|
+
var _a, _b;
|
|
69845
70204
|
const initialValue = React__default.useMemo(() => {
|
|
69846
|
-
var _a2,
|
|
70205
|
+
var _a2, _b2, _c;
|
|
69847
70206
|
if (((_a2 = field == null ? void 0 : field.parser) == null ? void 0 : _a2.type) === "slatejson") {
|
|
69848
70207
|
return input.value.children;
|
|
69849
|
-
} else if ((_c = (
|
|
70208
|
+
} else if ((_c = (_b2 = input.value) == null ? void 0 : _b2.children) == null ? void 0 : _c.length) {
|
|
69850
70209
|
const normalized = input.value.children.map(helpers.normalize);
|
|
69851
70210
|
return normalized;
|
|
69852
70211
|
} else {
|
|
@@ -69854,7 +70213,16 @@ const RichEditor = ({ input, tinaForm, field }) => {
|
|
|
69854
70213
|
}
|
|
69855
70214
|
}, []);
|
|
69856
70215
|
const showFloatingToolbar = ((_a = field == null ? void 0 : field.overrides) == null ? void 0 : _a.showFloatingToolbar) !== false;
|
|
69857
|
-
const
|
|
70216
|
+
const builtPlugins = React__default.useMemo(
|
|
70217
|
+
() => {
|
|
70218
|
+
var _a2;
|
|
70219
|
+
return createEditorPlugins({
|
|
70220
|
+
headingLevels: (_a2 = field == null ? void 0 : field.overrides) == null ? void 0 : _a2.headingLevels
|
|
70221
|
+
});
|
|
70222
|
+
},
|
|
70223
|
+
[(_b = field == null ? void 0 : field.overrides) == null ? void 0 : _b.headingLevels]
|
|
70224
|
+
);
|
|
70225
|
+
const plugins = showFloatingToolbar ? builtPlugins : builtPlugins.filter((plugin) => plugin.key !== "floating-toolbar");
|
|
69858
70226
|
const editor = useCreateEditor({
|
|
69859
70227
|
plugins: [...plugins],
|
|
69860
70228
|
value: initialValue,
|
|
@@ -69896,8 +70264,9 @@ const RichEditor = ({ input, tinaForm, field }) => {
|
|
|
69896
70264
|
templates: field.templates,
|
|
69897
70265
|
overrides: (field == null ? void 0 : field.toolbarOverride) ? field.toolbarOverride : field.overrides
|
|
69898
70266
|
},
|
|
69899
|
-
/* @__PURE__ */ React__default.createElement(FixedToolbar, null, /* @__PURE__ */ React__default.createElement(FixedToolbarButtons, null))
|
|
69900
|
-
|
|
70267
|
+
/* @__PURE__ */ React__default.createElement(FixedToolbar, null, /* @__PURE__ */ React__default.createElement(FixedToolbarButtons, null)),
|
|
70268
|
+
/* @__PURE__ */ React__default.createElement(Editor$1, null)
|
|
70269
|
+
)))
|
|
69901
70270
|
));
|
|
69902
70271
|
};
|
|
69903
70272
|
const MdxFieldPlugin = {
|
|
@@ -69999,6 +70368,191 @@ function useLocalStorage(key, initialValue) {
|
|
|
69999
70368
|
};
|
|
70000
70369
|
return [storedValue, setValue];
|
|
70001
70370
|
}
|
|
70371
|
+
const MediaWorkflowOverlay = () => {
|
|
70372
|
+
const cms = useCMS$1();
|
|
70373
|
+
const { setCurrentBranch } = useBranchData();
|
|
70374
|
+
const [state, setState] = React.useState({ phase: "idle" });
|
|
70375
|
+
const preflightAbortRef = React.useRef(null);
|
|
70376
|
+
const abortPreflight = React.useCallback(() => {
|
|
70377
|
+
var _a;
|
|
70378
|
+
(_a = preflightAbortRef.current) == null ? void 0 : _a.abort();
|
|
70379
|
+
preflightAbortRef.current = null;
|
|
70380
|
+
}, []);
|
|
70381
|
+
React.useEffect(() => {
|
|
70382
|
+
const offConfirm = cms.events.subscribe(
|
|
70383
|
+
"media:workflow:confirm-branch",
|
|
70384
|
+
(event) => {
|
|
70385
|
+
abortPreflight();
|
|
70386
|
+
setState({
|
|
70387
|
+
phase: "confirming",
|
|
70388
|
+
branchName: event.branchName,
|
|
70389
|
+
baseBranch: event.baseBranch,
|
|
70390
|
+
onConfirm: event.onConfirm,
|
|
70391
|
+
onCancel: event.onCancel,
|
|
70392
|
+
onSaveToProtectedBranch: event.onSaveToProtectedBranch
|
|
70393
|
+
});
|
|
70394
|
+
}
|
|
70395
|
+
);
|
|
70396
|
+
const offStart = cms.events.subscribe("media:workflow:start", () => {
|
|
70397
|
+
setState({ phase: "executing", step: 1, elapsed: 0 });
|
|
70398
|
+
});
|
|
70399
|
+
const offStep = cms.events.subscribe(
|
|
70400
|
+
"media:workflow:step",
|
|
70401
|
+
(event) => {
|
|
70402
|
+
setState(
|
|
70403
|
+
(prev) => prev.phase === "executing" ? { ...prev, step: event.step } : { phase: "executing", step: event.step, elapsed: 0 }
|
|
70404
|
+
);
|
|
70405
|
+
}
|
|
70406
|
+
);
|
|
70407
|
+
const offComplete = cms.events.subscribe("media:workflow:complete", (event) => {
|
|
70408
|
+
setCurrentBranch(event.branchName);
|
|
70409
|
+
});
|
|
70410
|
+
const offError = cms.events.subscribe(
|
|
70411
|
+
"media:workflow:error",
|
|
70412
|
+
(event) => {
|
|
70413
|
+
setState({ phase: "error", message: event.message });
|
|
70414
|
+
}
|
|
70415
|
+
);
|
|
70416
|
+
const offFinish = cms.events.subscribe("media:workflow:finish", () => {
|
|
70417
|
+
setState({ phase: "idle" });
|
|
70418
|
+
});
|
|
70419
|
+
return () => {
|
|
70420
|
+
offConfirm();
|
|
70421
|
+
offStart();
|
|
70422
|
+
offStep();
|
|
70423
|
+
offComplete();
|
|
70424
|
+
offError();
|
|
70425
|
+
offFinish();
|
|
70426
|
+
abortPreflight();
|
|
70427
|
+
};
|
|
70428
|
+
}, [abortPreflight, cms, setCurrentBranch]);
|
|
70429
|
+
React.useEffect(() => {
|
|
70430
|
+
if (state.phase !== "executing")
|
|
70431
|
+
return;
|
|
70432
|
+
const interval = setInterval(() => {
|
|
70433
|
+
setState(
|
|
70434
|
+
(prev) => prev.phase === "executing" ? { ...prev, elapsed: prev.elapsed + 1 } : prev
|
|
70435
|
+
);
|
|
70436
|
+
}, 1e3);
|
|
70437
|
+
return () => clearInterval(interval);
|
|
70438
|
+
}, [state.phase]);
|
|
70439
|
+
const handleCreateBranch = async () => {
|
|
70440
|
+
if (state.phase !== "confirming")
|
|
70441
|
+
return;
|
|
70442
|
+
const confirmState = state;
|
|
70443
|
+
const branchName = confirmState.branchName;
|
|
70444
|
+
const targetBranch = `tina/${branchName}`;
|
|
70445
|
+
abortPreflight();
|
|
70446
|
+
const abortController = new AbortController();
|
|
70447
|
+
preflightAbortRef.current = abortController;
|
|
70448
|
+
setState({
|
|
70449
|
+
...confirmState,
|
|
70450
|
+
isChecking: true,
|
|
70451
|
+
errorMessage: ""
|
|
70452
|
+
});
|
|
70453
|
+
const baseBranchExists = await checkBaseBranchExists(
|
|
70454
|
+
cms.api.tina,
|
|
70455
|
+
confirmState.baseBranch,
|
|
70456
|
+
"media workflow",
|
|
70457
|
+
abortController.signal
|
|
70458
|
+
);
|
|
70459
|
+
if (abortController.signal.aborted)
|
|
70460
|
+
return;
|
|
70461
|
+
if (!baseBranchExists) {
|
|
70462
|
+
if (preflightAbortRef.current === abortController) {
|
|
70463
|
+
preflightAbortRef.current = null;
|
|
70464
|
+
}
|
|
70465
|
+
setState({
|
|
70466
|
+
...confirmState,
|
|
70467
|
+
branchName,
|
|
70468
|
+
isChecking: false,
|
|
70469
|
+
errorMessage: `The branch ${confirmState.baseBranch} no longer exists. It may have been merged or deleted. Your changes cannot be pushed to it.`
|
|
70470
|
+
});
|
|
70471
|
+
return;
|
|
70472
|
+
}
|
|
70473
|
+
const targetBranchExists = await checkTargetBranchExists(
|
|
70474
|
+
cms.api.tina,
|
|
70475
|
+
targetBranch,
|
|
70476
|
+
"media workflow",
|
|
70477
|
+
abortController.signal
|
|
70478
|
+
);
|
|
70479
|
+
if (abortController.signal.aborted)
|
|
70480
|
+
return;
|
|
70481
|
+
if (targetBranchExists) {
|
|
70482
|
+
if (preflightAbortRef.current === abortController) {
|
|
70483
|
+
preflightAbortRef.current = null;
|
|
70484
|
+
}
|
|
70485
|
+
setState({
|
|
70486
|
+
...confirmState,
|
|
70487
|
+
branchName,
|
|
70488
|
+
isChecking: false,
|
|
70489
|
+
errorMessage: TARGET_BRANCH_EXISTS_ERROR
|
|
70490
|
+
});
|
|
70491
|
+
return;
|
|
70492
|
+
}
|
|
70493
|
+
try {
|
|
70494
|
+
if (preflightAbortRef.current === abortController) {
|
|
70495
|
+
preflightAbortRef.current = null;
|
|
70496
|
+
}
|
|
70497
|
+
setState({ phase: "executing", step: 1, elapsed: 0 });
|
|
70498
|
+
await confirmState.onConfirm(targetBranch);
|
|
70499
|
+
} catch (e) {
|
|
70500
|
+
console.error(e);
|
|
70501
|
+
setState({
|
|
70502
|
+
...confirmState,
|
|
70503
|
+
branchName,
|
|
70504
|
+
isChecking: false,
|
|
70505
|
+
errorMessage: getEditorialWorkflowErrorMessage(e)
|
|
70506
|
+
});
|
|
70507
|
+
}
|
|
70508
|
+
};
|
|
70509
|
+
if (state.phase === "idle")
|
|
70510
|
+
return null;
|
|
70511
|
+
if (state.phase === "confirming") {
|
|
70512
|
+
return /* @__PURE__ */ React.createElement(
|
|
70513
|
+
CreateBranchPromptModal,
|
|
70514
|
+
{
|
|
70515
|
+
branchName: state.branchName,
|
|
70516
|
+
close: () => {
|
|
70517
|
+
abortPreflight();
|
|
70518
|
+
state.onCancel();
|
|
70519
|
+
setState({ phase: "idle" });
|
|
70520
|
+
},
|
|
70521
|
+
disabled: state.branchName === "" || state.isChecking,
|
|
70522
|
+
errorMessage: state.errorMessage,
|
|
70523
|
+
onBranchNameChange: (branchName) => {
|
|
70524
|
+
abortPreflight();
|
|
70525
|
+
setState(
|
|
70526
|
+
(prev) => prev.phase === "confirming" ? {
|
|
70527
|
+
...prev,
|
|
70528
|
+
branchName,
|
|
70529
|
+
errorMessage: void 0,
|
|
70530
|
+
isChecking: false
|
|
70531
|
+
} : prev
|
|
70532
|
+
);
|
|
70533
|
+
},
|
|
70534
|
+
onCreateBranch: handleCreateBranch,
|
|
70535
|
+
onSaveToProtectedBranch: () => {
|
|
70536
|
+
abortPreflight();
|
|
70537
|
+
state.onSaveToProtectedBranch();
|
|
70538
|
+
setState({ phase: "idle" });
|
|
70539
|
+
}
|
|
70540
|
+
}
|
|
70541
|
+
);
|
|
70542
|
+
}
|
|
70543
|
+
if (state.phase === "executing") {
|
|
70544
|
+
return /* @__PURE__ */ React.createElement(
|
|
70545
|
+
EditorialWorkflowProgressModal,
|
|
70546
|
+
{
|
|
70547
|
+
title: "Save changes to new branch",
|
|
70548
|
+
currentStep: state.step,
|
|
70549
|
+
elapsedTime: state.elapsed
|
|
70550
|
+
}
|
|
70551
|
+
);
|
|
70552
|
+
}
|
|
70553
|
+
const dismissError = () => setState({ phase: "idle" });
|
|
70554
|
+
return /* @__PURE__ */ React.createElement(Modal, { className: "flex" }, /* @__PURE__ */ React.createElement(PopupModal, { className: "w-auto" }, /* @__PURE__ */ React.createElement(ModalHeader, { close: dismissError }, "Branch creation failed"), /* @__PURE__ */ React.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1 text-red-700 py-2 px-3 bg-red-50 border border-red-200 rounded max-w-sm" }, /* @__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:"), " ", state.message)))));
|
|
70555
|
+
};
|
|
70002
70556
|
function asyncPoll(fn, pollInterval = 5 * 1e3, pollTimeout = 30 * 1e3) {
|
|
70003
70557
|
const endTime = (/* @__PURE__ */ new Date()).getTime() + pollTimeout;
|
|
70004
70558
|
let stop = false;
|
|
@@ -70558,7 +71112,7 @@ mutation addPendingDocumentMutation(
|
|
|
70558
71112
|
}
|
|
70559
71113
|
});
|
|
70560
71114
|
if (!res.ok) {
|
|
70561
|
-
let errorMessage = `There was an error creating a
|
|
71115
|
+
let errorMessage = `There was an error creating a pull request. ${res.statusText}`;
|
|
70562
71116
|
if (res.status === 422) {
|
|
70563
71117
|
errorMessage = `Please make sure you have made changes on ${branch} before creating a pull request.`;
|
|
70564
71118
|
}
|
|
@@ -70567,7 +71121,7 @@ mutation addPendingDocumentMutation(
|
|
|
70567
71121
|
const values = await res.json();
|
|
70568
71122
|
return values;
|
|
70569
71123
|
} catch (error2) {
|
|
70570
|
-
console.error("There was an error creating a
|
|
71124
|
+
console.error("There was an error creating a pull request.", error2);
|
|
70571
71125
|
throw error2;
|
|
70572
71126
|
}
|
|
70573
71127
|
}
|
|
@@ -70664,7 +71218,8 @@ mutation addPendingDocumentMutation(
|
|
|
70664
71218
|
try {
|
|
70665
71219
|
const url = `${this.contentApiBase}/github/${this.clientId}/list_branches`;
|
|
70666
71220
|
const res = await this.authProvider.fetchWithToken(url, {
|
|
70667
|
-
method: "GET"
|
|
71221
|
+
method: "GET",
|
|
71222
|
+
signal: args == null ? void 0 : args.signal
|
|
70668
71223
|
});
|
|
70669
71224
|
const branches = await res.json();
|
|
70670
71225
|
const parsedBranches = await ListBranchResponse.parseAsync(branches);
|
|
@@ -70690,10 +71245,13 @@ mutation addPendingDocumentMutation(
|
|
|
70690
71245
|
var _a;
|
|
70691
71246
|
return this.usingEditorialWorkflow && ((_a = this.protectedBranches) == null ? void 0 : _a.includes(decodeURIComponent(this.branch)));
|
|
70692
71247
|
}
|
|
70693
|
-
async branchExists(branchName) {
|
|
71248
|
+
async branchExists(branchName, args) {
|
|
70694
71249
|
if (this.isLocalMode)
|
|
70695
71250
|
return true;
|
|
70696
|
-
const branches = await this.listBranches({
|
|
71251
|
+
const branches = await this.listBranches({
|
|
71252
|
+
includeIndexStatus: false,
|
|
71253
|
+
signal: args == null ? void 0 : args.signal
|
|
71254
|
+
});
|
|
70697
71255
|
return branches.some((b) => b.name === branchName);
|
|
70698
71256
|
}
|
|
70699
71257
|
async createBranch({ baseBranch, branchName }) {
|
|
@@ -70737,6 +71295,89 @@ mutation addPendingDocumentMutation(
|
|
|
70737
71295
|
throw error2;
|
|
70738
71296
|
}
|
|
70739
71297
|
}
|
|
71298
|
+
async pollEditorialWorkflowStatus(requestId, onStatusUpdate) {
|
|
71299
|
+
const pollInterval = 5e3;
|
|
71300
|
+
const maxAttempts = 180;
|
|
71301
|
+
let attempts = 0;
|
|
71302
|
+
while (attempts < maxAttempts) {
|
|
71303
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
71304
|
+
attempts++;
|
|
71305
|
+
try {
|
|
71306
|
+
const statusUrl = `${this.contentApiBase}/editorial-workflow/${this.clientId}/status/${requestId}`;
|
|
71307
|
+
const statusResponse = await this.authProvider.fetchWithToken(statusUrl);
|
|
71308
|
+
const statusResponseBody = await statusResponse.json();
|
|
71309
|
+
onStatusUpdate == null ? void 0 : onStatusUpdate({
|
|
71310
|
+
status: statusResponseBody.status,
|
|
71311
|
+
message: statusResponseBody.message || `Status: ${statusResponseBody.status}`
|
|
71312
|
+
});
|
|
71313
|
+
if (statusResponseBody.status === EDITORIAL_WORKFLOW_STATUS.ERROR || statusResponse.status === 500) {
|
|
71314
|
+
if (statusResponseBody.pullRequestUrl) {
|
|
71315
|
+
return {
|
|
71316
|
+
branchName: statusResponseBody.branchName,
|
|
71317
|
+
pullRequestUrl: statusResponseBody.pullRequestUrl,
|
|
71318
|
+
warning: statusResponseBody.message
|
|
71319
|
+
};
|
|
71320
|
+
}
|
|
71321
|
+
const error2 = new Error(
|
|
71322
|
+
statusResponseBody.message || "Editorial workflow failed"
|
|
71323
|
+
);
|
|
71324
|
+
error2.errorCode = statusResponseBody.errorCode || "WORKFLOW_FAILED";
|
|
71325
|
+
throw error2;
|
|
71326
|
+
}
|
|
71327
|
+
if (statusResponse.status === 200) {
|
|
71328
|
+
return {
|
|
71329
|
+
branchName: statusResponseBody.branchName,
|
|
71330
|
+
pullRequestUrl: statusResponseBody.pullRequestUrl
|
|
71331
|
+
};
|
|
71332
|
+
}
|
|
71333
|
+
if (statusResponse.status !== 202) {
|
|
71334
|
+
const error2 = new Error(
|
|
71335
|
+
statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText}`
|
|
71336
|
+
);
|
|
71337
|
+
error2.errorCode = "WORKFLOW_STATUS_FAILED";
|
|
71338
|
+
throw error2;
|
|
71339
|
+
}
|
|
71340
|
+
} catch (error2) {
|
|
71341
|
+
if (error2.errorCode) {
|
|
71342
|
+
throw error2;
|
|
71343
|
+
}
|
|
71344
|
+
console.warn(
|
|
71345
|
+
`Editorial workflow status poll failed (attempt ${attempts}/${maxAttempts}), retrying...`,
|
|
71346
|
+
error2
|
|
71347
|
+
);
|
|
71348
|
+
}
|
|
71349
|
+
}
|
|
71350
|
+
const timeoutMinutes = Math.round(maxAttempts * pollInterval / 6e4);
|
|
71351
|
+
throw new Error(
|
|
71352
|
+
`Editorial workflow timed out after ${timeoutMinutes} minutes. It may still be completing in the background — please wait before retrying.`
|
|
71353
|
+
);
|
|
71354
|
+
}
|
|
71355
|
+
toEditorialWorkflowError(responseBody, fallbackMessage) {
|
|
71356
|
+
const error2 = new Error(
|
|
71357
|
+
(responseBody == null ? void 0 : responseBody.message) || fallbackMessage
|
|
71358
|
+
);
|
|
71359
|
+
if (responseBody == null ? void 0 : responseBody.errorCode) {
|
|
71360
|
+
error2.errorCode = responseBody.errorCode;
|
|
71361
|
+
}
|
|
71362
|
+
if (responseBody == null ? void 0 : responseBody.conflictingBranch) {
|
|
71363
|
+
error2.conflictingBranch = responseBody.conflictingBranch;
|
|
71364
|
+
}
|
|
71365
|
+
return error2;
|
|
71366
|
+
}
|
|
71367
|
+
async postEditorialWorkflow(url, body, errorFallback) {
|
|
71368
|
+
const res = await this.authProvider.fetchWithToken(url, {
|
|
71369
|
+
method: "POST",
|
|
71370
|
+
body: JSON.stringify(body),
|
|
71371
|
+
headers: {
|
|
71372
|
+
"Content-Type": "application/json"
|
|
71373
|
+
}
|
|
71374
|
+
});
|
|
71375
|
+
const responseBody = await res.json();
|
|
71376
|
+
if (!res.ok) {
|
|
71377
|
+
throw this.toEditorialWorkflowError(responseBody, errorFallback);
|
|
71378
|
+
}
|
|
71379
|
+
return responseBody;
|
|
71380
|
+
}
|
|
70740
71381
|
/**
|
|
70741
71382
|
* Initiate and poll for the results of an editorial workflow operation
|
|
70742
71383
|
*
|
|
@@ -70746,32 +71387,16 @@ mutation addPendingDocumentMutation(
|
|
|
70746
71387
|
async executeEditorialWorkflow(options) {
|
|
70747
71388
|
const url = `${this.contentApiBase}/editorial-workflow/${this.clientId}`;
|
|
70748
71389
|
try {
|
|
70749
|
-
const
|
|
70750
|
-
|
|
70751
|
-
|
|
71390
|
+
const responseBody = await this.postEditorialWorkflow(
|
|
71391
|
+
url,
|
|
71392
|
+
{
|
|
70752
71393
|
branchName: options.branchName,
|
|
70753
71394
|
baseBranch: options.baseBranch,
|
|
70754
71395
|
prTitle: options.prTitle,
|
|
70755
71396
|
graphQLContentOp: options.graphQLContentOp
|
|
70756
|
-
}
|
|
70757
|
-
|
|
70758
|
-
|
|
70759
|
-
}
|
|
70760
|
-
});
|
|
70761
|
-
const responseBody = await res.json();
|
|
70762
|
-
if (!res.ok) {
|
|
70763
|
-
console.error("There was an error starting editorial workflow.");
|
|
70764
|
-
const error2 = new Error(
|
|
70765
|
-
(responseBody == null ? void 0 : responseBody.message) || "Failed to start editorial workflow"
|
|
70766
|
-
);
|
|
70767
|
-
if (responseBody == null ? void 0 : responseBody.errorCode) {
|
|
70768
|
-
error2.errorCode = responseBody.errorCode;
|
|
70769
|
-
}
|
|
70770
|
-
if (responseBody == null ? void 0 : responseBody.conflictingBranch) {
|
|
70771
|
-
error2.conflictingBranch = responseBody.conflictingBranch;
|
|
70772
|
-
}
|
|
70773
|
-
throw error2;
|
|
70774
|
-
}
|
|
71397
|
+
},
|
|
71398
|
+
"Failed to start editorial workflow"
|
|
71399
|
+
);
|
|
70775
71400
|
const requestId = responseBody.requestId;
|
|
70776
71401
|
if (!requestId) {
|
|
70777
71402
|
return responseBody;
|
|
@@ -70782,60 +71407,10 @@ mutation addPendingDocumentMutation(
|
|
|
70782
71407
|
message: "Workflow queued, starting..."
|
|
70783
71408
|
});
|
|
70784
71409
|
}
|
|
70785
|
-
|
|
70786
|
-
|
|
70787
|
-
|
|
70788
|
-
|
|
70789
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
70790
|
-
attempts++;
|
|
70791
|
-
try {
|
|
70792
|
-
const statusUrl = `${this.contentApiBase}/editorial-workflow/${this.clientId}/status/${requestId}`;
|
|
70793
|
-
const statusResponse = await this.authProvider.fetchWithToken(statusUrl);
|
|
70794
|
-
const statusResponseBody = await statusResponse.json();
|
|
70795
|
-
if (options.onStatusUpdate) {
|
|
70796
|
-
options.onStatusUpdate({
|
|
70797
|
-
status: statusResponseBody.status,
|
|
70798
|
-
message: statusResponseBody.message || `Status: ${statusResponseBody.status}`
|
|
70799
|
-
});
|
|
70800
|
-
}
|
|
70801
|
-
if (statusResponseBody.status === EDITORIAL_WORKFLOW_STATUS.ERROR || statusResponse.status === 500) {
|
|
70802
|
-
if (statusResponseBody.pullRequestUrl) {
|
|
70803
|
-
return {
|
|
70804
|
-
branchName: statusResponseBody.branchName,
|
|
70805
|
-
pullRequestUrl: statusResponseBody.pullRequestUrl,
|
|
70806
|
-
warning: statusResponseBody.message
|
|
70807
|
-
};
|
|
70808
|
-
}
|
|
70809
|
-
const error2 = new Error(
|
|
70810
|
-
statusResponseBody.message || "Editorial workflow failed"
|
|
70811
|
-
);
|
|
70812
|
-
error2.errorCode = statusResponseBody.errorCode || "WORKFLOW_FAILED";
|
|
70813
|
-
throw error2;
|
|
70814
|
-
}
|
|
70815
|
-
if (statusResponse.status === 200) {
|
|
70816
|
-
return {
|
|
70817
|
-
branchName: statusResponseBody.branchName,
|
|
70818
|
-
pullRequestUrl: statusResponseBody.pullRequestUrl
|
|
70819
|
-
};
|
|
70820
|
-
}
|
|
70821
|
-
if (statusResponse.status !== 202) {
|
|
70822
|
-
const error2 = new Error(
|
|
70823
|
-
statusResponseBody.message || `Failed to check workflow status: ${statusResponse.statusText}`
|
|
70824
|
-
);
|
|
70825
|
-
error2.errorCode = "WORKFLOW_STATUS_FAILED";
|
|
70826
|
-
throw error2;
|
|
70827
|
-
}
|
|
70828
|
-
} catch (error2) {
|
|
70829
|
-
if (error2.errorCode) {
|
|
70830
|
-
throw error2;
|
|
70831
|
-
}
|
|
70832
|
-
console.warn(
|
|
70833
|
-
`Editorial workflow status poll failed (attempt ${attempts}/${maxAttempts}), retrying...`,
|
|
70834
|
-
error2
|
|
70835
|
-
);
|
|
70836
|
-
}
|
|
70837
|
-
}
|
|
70838
|
-
throw new Error("Editorial workflow timed out after 5 minutes");
|
|
71410
|
+
return await this.pollEditorialWorkflowStatus(
|
|
71411
|
+
requestId,
|
|
71412
|
+
options.onStatusUpdate
|
|
71413
|
+
);
|
|
70839
71414
|
} catch (error2) {
|
|
70840
71415
|
console.error(
|
|
70841
71416
|
"There was an error with editorial workflow operation.",
|
|
@@ -70844,6 +71419,17 @@ mutation addPendingDocumentMutation(
|
|
|
70844
71419
|
throw error2;
|
|
70845
71420
|
}
|
|
70846
71421
|
}
|
|
71422
|
+
async startMediaEditorialWorkflow(options) {
|
|
71423
|
+
const url = `${this.contentApiBase}/editorial-workflow/${this.clientId}/media`;
|
|
71424
|
+
return await this.postEditorialWorkflow(
|
|
71425
|
+
url,
|
|
71426
|
+
options,
|
|
71427
|
+
"Failed to start media editorial workflow"
|
|
71428
|
+
);
|
|
71429
|
+
}
|
|
71430
|
+
async waitForEditorialWorkflowStatus(requestId, onStatusUpdate) {
|
|
71431
|
+
return await this.pollEditorialWorkflowStatus(requestId, onStatusUpdate);
|
|
71432
|
+
}
|
|
70847
71433
|
}
|
|
70848
71434
|
const DEFAULT_LOCAL_TINA_GQL_SERVER_URL = "http://localhost:4001/graphql";
|
|
70849
71435
|
class LocalClient extends Client {
|
|
@@ -71397,7 +71983,7 @@ const TinaCloudProvider = (props) => {
|
|
|
71397
71983
|
}, []);
|
|
71398
71984
|
React__default.useEffect(() => {
|
|
71399
71985
|
const setupEditorialWorkflow = () => {
|
|
71400
|
-
client.getProject().then((project) => {
|
|
71986
|
+
client.getProject().then(async (project) => {
|
|
71401
71987
|
var _a2;
|
|
71402
71988
|
if ((_a2 = project == null ? void 0 : project.features) == null ? void 0 : _a2.includes("editorial-workflow")) {
|
|
71403
71989
|
cms.flags.set("branch-switcher", true);
|
|
@@ -71427,7 +72013,7 @@ const TinaCloudProvider = (props) => {
|
|
|
71427
72013
|
setCurrentBranch(b);
|
|
71428
72014
|
}
|
|
71429
72015
|
},
|
|
71430
|
-
/* @__PURE__ */ React__default.createElement(TinaProvider, { cms }, /* @__PURE__ */ React__default.createElement(AuthWallInner, { ...props, cms }))
|
|
72016
|
+
/* @__PURE__ */ React__default.createElement(TinaProvider, { cms }, /* @__PURE__ */ React__default.createElement(MediaWorkflowOverlay, null), /* @__PURE__ */ React__default.createElement(AuthWallInner, { ...props, cms }))
|
|
71431
72017
|
));
|
|
71432
72018
|
};
|
|
71433
72019
|
const TinaCloudAuthWall = TinaCloudProvider;
|
|
@@ -73574,7 +74160,7 @@ const RenderForm$1 = ({
|
|
|
73574
74160
|
};
|
|
73575
74161
|
}
|
|
73576
74162
|
}
|
|
73577
|
-
const
|
|
74163
|
+
const defaultItem = customDefaults || // @ts-ignore internal types aren't up to date
|
|
73578
74164
|
((_d = template.ui) == null ? void 0 : _d.defaultItem) || // @ts-ignore
|
|
73579
74165
|
(template == null ? void 0 : template.defaultItem) || {};
|
|
73580
74166
|
const fileReadOnly = (_f = (_e = schemaCollection == null ? void 0 : schemaCollection.ui) == null ? void 0 : _e.filename) == null ? void 0 : _f.readonly;
|
|
@@ -73630,7 +74216,7 @@ const RenderForm$1 = ({
|
|
|
73630
74216
|
const folderName = folder.fullyQualifiedName ? folder.name : "";
|
|
73631
74217
|
return new Form({
|
|
73632
74218
|
crudType: "create",
|
|
73633
|
-
initialValues: typeof
|
|
74219
|
+
initialValues: typeof defaultItem === "function" ? { ...defaultItem(), _template: templateName } : { ...defaultItem, _template: templateName },
|
|
73634
74220
|
extraSubscribeValues: { active: true, submitting: true, touched: true },
|
|
73635
74221
|
onChange: (values) => {
|
|
73636
74222
|
var _a3, _b3;
|
|
@@ -74462,6 +75048,7 @@ export {
|
|
|
74462
75048
|
ColorPicker,
|
|
74463
75049
|
CreateBranchModal,
|
|
74464
75050
|
CreateBranchModel,
|
|
75051
|
+
CreateBranchPromptModal,
|
|
74465
75052
|
CursorPaginator,
|
|
74466
75053
|
DEFAULT_LOCAL_TINA_GQL_SERVER_URL,
|
|
74467
75054
|
DEFAULT_MEDIA_UPLOAD_TYPES,
|
|
@@ -74540,6 +75127,7 @@ export {
|
|
|
74540
75127
|
MediaIcon,
|
|
74541
75128
|
MediaListError,
|
|
74542
75129
|
MediaManager$1 as MediaManager,
|
|
75130
|
+
MediaWorkflowOverlay,
|
|
74543
75131
|
Message,
|
|
74544
75132
|
Modal,
|
|
74545
75133
|
ModalActions,
|
|
@@ -74639,6 +75227,7 @@ export {
|
|
|
74639
75227
|
passwordFieldClasses,
|
|
74640
75228
|
resolveField,
|
|
74641
75229
|
safeAssertShape,
|
|
75230
|
+
sanitizeFilename,
|
|
74642
75231
|
selectFieldClasses,
|
|
74643
75232
|
sortBranchListFn,
|
|
74644
75233
|
staticRequest,
|