tinacms 3.12.0 → 3.13.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/admin/components/GetDocument.d.ts +1 -1
- package/dist/admin/components/UnableToLoadModal.d.ts +4 -0
- package/dist/index.js +1798 -1045
- package/dist/internalClient/authProvider.d.ts +8 -0
- package/dist/internalClient/index.d.ts +14 -2
- package/dist/internalClient/types.d.ts +11 -0
- package/dist/rich-text/index.js +35 -35
- package/dist/rich-text/static.js +40 -37
- package/dist/toolkit/alerts/alerts.d.ts +7 -1
- package/dist/toolkit/components/media/media-manager.d.ts +3 -1
- package/dist/toolkit/components/media/utils.d.ts +12 -0
- package/dist/toolkit/core/cms.d.ts +2 -2
- package/dist/toolkit/core/errors.d.ts +1 -0
- package/dist/toolkit/core/index.d.ts +2 -0
- package/dist/toolkit/core/media-store.default.d.ts +41 -15
- package/dist/toolkit/core/media.d.ts +18 -0
- package/dist/toolkit/core/session-expired.d.ts +6 -0
- package/dist/toolkit/fields/components/image-upload/image-upload.d.ts +2 -0
- package/dist/toolkit/fields/plugins/blocks-field-plugin/block-selector-big.d.ts +2 -1
- package/dist/toolkit/fields/plugins/blocks-field-plugin/block-selector.d.ts +2 -1
- package/dist/toolkit/fields/plugins/field-props.d.ts +12 -1
- package/dist/toolkit/fields/plugins/group-list-field-plugin.d.ts +2 -1
- package/dist/toolkit/fields/plugins/image-field-plugin.d.ts +2 -0
- package/dist/toolkit/fields/plugins/mdx-field-plugin/index.d.ts +5 -1
- package/dist/toolkit/fields/plugins/mdx-field-plugin/plate/plugins/create-html-block/index.d.ts +2 -2
- package/dist/toolkit/form-builder/create-branch-modal.d.ts +2 -1
- package/dist/toolkit/form-builder/editorial-workflow-utils.d.ts +2 -0
- package/dist/toolkit/index.d.ts +1 -1
- package/dist/toolkit/plugin-branch-switcher/branch-switcher-legacy.d.ts +1 -1
- package/dist/toolkit/plugin-branch-switcher/branch-switcher.d.ts +6 -2
- package/dist/utils/branch-name.d.ts +3 -0
- package/package.json +9 -10
- package/dist/toolkit/plugin-branch-switcher/format-branch-name.d.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -20,8 +20,7 @@ import { SlashInputPlugin, SlashPlugin } from "@udecode/plate-slash-command/reac
|
|
|
20
20
|
import { TablePlugin, TableRowPlugin, useTableCellElement, TableProvider, useTableElement, useTableMergeState, useTableBordersDropdownMenuContentState, TableCellPlugin, TableCellHeaderPlugin } from "@udecode/plate-table/react";
|
|
21
21
|
import { PlateElement, useReadOnly, useElement, PlateLeaf, useSelected, useFocused, useEditorRef, withRef as withRef$1, useComposedRef, useEditorPlugin, useElementSelector, withHOC, usePluginOption, useRemoveNodeButton, useEditorSelector, ParagraphPlugin, createPlatePlugin, PlateContent, PlateContainer, useEditorState, useMarkToolbarButtonState, useMarkToolbarButton, usePlateEditor, useFormInputProps, useEditorSelection, useEditorReadOnly, useOnClickOutside, useEventEditorValue, Plate } from "@udecode/plate/react";
|
|
22
22
|
import { isLangSupported, formatCodeBlock, insertEmptyCodeBlock, isCodeBlockEmpty, unwrapCodeBlock, isSelectionAtCodeBlockStart } from "@udecode/plate-code-block";
|
|
23
|
-
import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, Baseline, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleAlert, CircleCheck as CircleCheck$1, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
|
|
24
|
-
import mermaid from "mermaid";
|
|
23
|
+
import { X, Search, ChevronDown, Check, AlertTriangle, BracesIcon, Heading6 as Heading6$1, Heading5 as Heading5$1, Heading4 as Heading4$1, Heading3 as Heading3$1, Heading2 as Heading2$1, Heading1 as Heading1$1, ChevronRight, Twitter, SunMedium, Moon, SeparatorHorizontal, Eye, Link2Off, Underline, Trash, Text, Table as Table$1, Superscript, Subscript, Strikethrough, Highlighter, Settings, RectangleHorizontal, RotateCcw, Pilcrow, Outdent, MoreHorizontal, Minus, WrapText, Keyboard, Indent, ExternalLink, Smile, Edit2, GripVertical, MessageSquarePlus, MessageSquare, Ungroup, Combine, RectangleVertical, Baseline, FileCode, PaintBucket, ChevronsUpDown, Quote, AlignRight as AlignRight$1, AlignLeft as AlignLeft$1, AlignJustify, AlignCenter as AlignCenter$1, Plus, PaintBucketIcon, CombineIcon, SquareSplitHorizontalIcon, Grid2X2Icon, Trash2Icon, ArrowUp, ArrowDown, XIcon, ArrowLeft, ArrowRight, EraserIcon, Info, CircleAlert, CircleCheck as CircleCheck$1, CircleIcon, ChevronDownIcon as ChevronDownIcon$1, File as File$1, ChevronUp, Edit, Pencil, Clock, CalendarCheck, Calendar as Calendar$1, CalendarDays, RotateCw, ChevronLeft, WifiOff, TriangleAlert, RefreshCw, GitBranch, CircleHelp, Loader2, Lock, ArrowUpDown, GitFork, Globe, Copy, Folder as Folder$1, Clapperboard, LayoutGrid, List as List$1, CloudUpload, ArrowDownToLine, TextCursorInput, Images, AlertCircle, Image, Database, CheckCircle2, ImageOff, KeyRound, Cloud, LoaderCircle, ScrollText, RefreshCwOff, OctagonAlert, Menu, FilePlus, LogOut, FileStack, FolderOpen, History, Users, PanelLeft, Files, User, FileText, GitBranchIcon, Circle as Circle$1, ListOrdered, Grid3x3Icon, CircleX, Link, Unlink, SquarePen, Trash2, House, Unlock } from "lucide-react";
|
|
25
24
|
import { Slot } from "@radix-ui/react-slot";
|
|
26
25
|
import { cva } from "class-variance-authority";
|
|
27
26
|
import { Command as Command$2 } from "cmdk";
|
|
@@ -33,7 +32,7 @@ import { useHTMLInputCursorState, useComboboxInput } from "@udecode/plate-combob
|
|
|
33
32
|
import { useComboboxContext, Combobox as Combobox$1, useComboboxStore, ComboboxProvider, Portal, ComboboxPopover, ComboboxItem } from "@ariakit/react";
|
|
34
33
|
import { filterWords } from "@udecode/plate-combobox";
|
|
35
34
|
import { toggleList, unwrapList, getListItemEntry } from "@udecode/plate-list";
|
|
36
|
-
import { normalizeHeadingLevels, ALL_HEADING_LEVELS, ASYNC_POLLER_ERROR, canonicalPath, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
|
|
35
|
+
import { normalizeHeadingLevels, ALL_HEADING_LEVELS, MEDIA_MIME_TYPES, extensionOf, resolveMediaAccept, ASYNC_POLLER_ERROR, MEDIA_CATEGORIES, canonicalPath, ERR_BRANCH_EXISTS, ERR_BRANCH_CONFLICT, isHeadingLevel, TinaSchema, addNamespaceToSchema, parseURL, ERR_HAS_REFERENCES, ERR_ALREADY_EXISTS, isValidRelativePath, RELATIVE_PATH_ALLOWED_CHARS_MESSAGE, resolveForm, RELATIVE_PATH_REGEX, normalizePath, ERR_NOT_INDEXED, validateSchema } from "@tinacms/schema-tools";
|
|
37
36
|
import { NAMER, resolveField } from "@tinacms/schema-tools";
|
|
38
37
|
import { useBlockSelected, BlockSelectionPlugin } from "@udecode/plate-selection/react";
|
|
39
38
|
import "@udecode/plate-dnd";
|
|
@@ -52,8 +51,9 @@ import PropTypes from "prop-types";
|
|
|
52
51
|
import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCenter } from "@dnd-kit/core";
|
|
53
52
|
import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable, defaultAnimateLayoutChanges } from "@dnd-kit/sortable";
|
|
54
53
|
import { CSS } from "@dnd-kit/utilities";
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
54
|
+
import { buildSchema, print, getIntrospectionQuery, buildClientSchema, parse as parse$3 } from "graphql";
|
|
55
|
+
import { diff as diff$1 } from "@graphql-inspector/core";
|
|
56
|
+
import { processDocumentForIndexing, queryToSearchIndexQuery, optionsToSearchIndexOptions, parseSearchIndexResponse } from "@tinacms/search/index-client";
|
|
57
57
|
import { HexColorPicker } from "react-colorful";
|
|
58
58
|
import { Command as Command$3 } from "@udecode/cmdk";
|
|
59
59
|
import { isHotkey } from "is-hotkey";
|
|
@@ -62,19 +62,18 @@ import { ExitBreakPlugin, SoftBreakPlugin } from "@udecode/plate-break/react";
|
|
|
62
62
|
import { ResetNodePlugin } from "@udecode/plate-reset-node/react";
|
|
63
63
|
import { TrailingBlockPlugin } from "@udecode/plate-trailing-block";
|
|
64
64
|
import { BaseBlockquotePlugin } from "@udecode/plate-block-quote";
|
|
65
|
+
import { autoformatSmartQuotes, autoformatPunctuation, autoformatLegal, autoformatArrow, autoformatMath } from "@udecode/plate-autoformat";
|
|
65
66
|
import { HeadingPlugin } from "@udecode/plate-heading/react";
|
|
66
67
|
import { IndentListPlugin } from "@udecode/plate-indent-list/react";
|
|
67
68
|
import { NodeIdPlugin } from "@udecode/plate-node-id";
|
|
68
69
|
import { offset, flip, shift, limitShift, useVirtualFloating, getSelectionBoundingClientRect } from "@udecode/plate-floating";
|
|
69
70
|
import { getLinkAttributes } from "@udecode/plate-link";
|
|
70
|
-
import { autoformatSmartQuotes, autoformatPunctuation, autoformatLegal, autoformatArrow, autoformatMath } from "@udecode/plate-autoformat";
|
|
71
71
|
import * as yup from "yup";
|
|
72
|
+
import { format as format$3, formatDistanceToNow } from "date-fns";
|
|
72
73
|
import { enUS } from "date-fns/locale";
|
|
73
74
|
import { DayPicker } from "react-day-picker";
|
|
74
75
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
75
|
-
import {
|
|
76
|
-
import { diff as diff$1 } from "@graphql-inspector/core";
|
|
77
|
-
import { processDocumentForIndexing, queryToSearchIndexQuery, optionsToSearchIndexOptions, parseSearchIndexResponse } from "@tinacms/search/index-client";
|
|
76
|
+
import { useReactTable, getSortedRowModel, getCoreRowModel, flexRender, getExpandedRowModel, getFilteredRowModel } from "@tanstack/react-table";
|
|
78
77
|
import * as dropzone from "react-dropzone";
|
|
79
78
|
import gql from "graphql-tag";
|
|
80
79
|
import { useLocation, NavLink, useNavigate, useParams, Navigate, Link as Link$1, HashRouter, Routes, Route } from "react-router-dom";
|
|
@@ -1396,20 +1395,6 @@ function CodeBlockCombobox({
|
|
|
1396
1395
|
)))))
|
|
1397
1396
|
));
|
|
1398
1397
|
}
|
|
1399
|
-
const MermaidElementWithRef = ({ config }) => {
|
|
1400
|
-
const mermaidRef = useRef(null);
|
|
1401
|
-
useEffect(() => {
|
|
1402
|
-
if (mermaidRef.current) {
|
|
1403
|
-
const renderMermaid = async () => {
|
|
1404
|
-
await mermaid.run({
|
|
1405
|
-
nodes: [mermaidRef.current.querySelector(".mermaid")]
|
|
1406
|
-
});
|
|
1407
|
-
};
|
|
1408
|
-
renderMermaid();
|
|
1409
|
-
}
|
|
1410
|
-
}, [config]);
|
|
1411
|
-
return /* @__PURE__ */ React__default.createElement("div", { contentEditable: false, className: "border-border border-b pt-10" }, /* @__PURE__ */ React__default.createElement("div", { ref: mermaidRef }, /* @__PURE__ */ React__default.createElement("pre", { className: "mermaid not-tina-prose" }, config)));
|
|
1412
|
-
};
|
|
1413
1398
|
function ErrorMessage$1({ error }) {
|
|
1414
1399
|
if (!error) return null;
|
|
1415
1400
|
return /* @__PURE__ */ React__default.createElement(
|
|
@@ -1423,6 +1408,52 @@ function ErrorMessage$1({ error }) {
|
|
|
1423
1408
|
/* @__PURE__ */ React__default.createElement("div", { className: "ml-3 flex-1" }, /* @__PURE__ */ React__default.createElement("pre", { className: "m-0 font-mono text-sm text-red-700 whitespace-pre-wrap break-words" }, error))
|
|
1424
1409
|
);
|
|
1425
1410
|
}
|
|
1411
|
+
const RENDERER_FAILED = "The diagram renderer did not load.";
|
|
1412
|
+
const MermaidElementWithRef = ({ config }) => {
|
|
1413
|
+
const mermaidRef = useRef(null);
|
|
1414
|
+
const [status, setStatus] = useState("loading");
|
|
1415
|
+
const [error, setError] = useState(null);
|
|
1416
|
+
useEffect(() => {
|
|
1417
|
+
let isCancelled = false;
|
|
1418
|
+
setStatus("loading");
|
|
1419
|
+
const render = async () => {
|
|
1420
|
+
var _a;
|
|
1421
|
+
try {
|
|
1422
|
+
const node = (_a = mermaidRef.current) == null ? void 0 : _a.querySelector(".mermaid");
|
|
1423
|
+
if (!node) throw new Error(RENDERER_FAILED);
|
|
1424
|
+
const { default: mermaid } = await import("mermaid");
|
|
1425
|
+
await mermaid.run({ nodes: [node] });
|
|
1426
|
+
if (!isCancelled) {
|
|
1427
|
+
setError(null);
|
|
1428
|
+
setStatus("ready");
|
|
1429
|
+
}
|
|
1430
|
+
} catch (cause) {
|
|
1431
|
+
if (isCancelled) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
if (cause instanceof Error) {
|
|
1435
|
+
setError(cause.message || RENDERER_FAILED);
|
|
1436
|
+
} else {
|
|
1437
|
+
setError(RENDERER_FAILED);
|
|
1438
|
+
}
|
|
1439
|
+
setStatus("failed");
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
render();
|
|
1443
|
+
return () => {
|
|
1444
|
+
isCancelled = true;
|
|
1445
|
+
};
|
|
1446
|
+
}, [config]);
|
|
1447
|
+
return /* @__PURE__ */ React__default.createElement("div", { contentEditable: false, className: "border-border border-b pt-10" }, /* @__PURE__ */ React__default.createElement("div", { className: "relative" }, /* @__PURE__ */ React__default.createElement(
|
|
1448
|
+
"div",
|
|
1449
|
+
{
|
|
1450
|
+
ref: mermaidRef,
|
|
1451
|
+
className: status === "loading" ? "opacity-0" : void 0
|
|
1452
|
+
},
|
|
1453
|
+
/* @__PURE__ */ React__default.createElement("pre", { className: "mermaid not-tina-prose" }, config)
|
|
1454
|
+
), status === "loading" && /* @__PURE__ */ React__default.createElement("div", { className: "absolute inset-0 flex items-center justify-center text-sm text-muted-foreground" }, "Loading diagram…")), status === "failed" && /* @__PURE__ */ React__default.createElement(ErrorMessage$1, { error }));
|
|
1455
|
+
};
|
|
1456
|
+
const PARSE_FAILED = "An error occurred while parsing the diagram.";
|
|
1426
1457
|
function codeLineToString(content) {
|
|
1427
1458
|
return (content.children || []).map(
|
|
1428
1459
|
(line) => (line.children || []).map((textNode) => textNode.text).join("")
|
|
@@ -1440,17 +1471,21 @@ const CodeBlockElement = withRef(
|
|
|
1440
1471
|
let isCancelled = false;
|
|
1441
1472
|
const validateMermaid = async () => {
|
|
1442
1473
|
try {
|
|
1474
|
+
const { default: mermaid } = await import("mermaid");
|
|
1443
1475
|
await mermaid.parse(
|
|
1444
1476
|
codeLineToString(element)
|
|
1445
1477
|
);
|
|
1446
1478
|
if (!isCancelled) {
|
|
1447
1479
|
setCodeBlockError(null);
|
|
1448
1480
|
}
|
|
1449
|
-
} catch (
|
|
1450
|
-
if (
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1481
|
+
} catch (cause) {
|
|
1482
|
+
if (isCancelled) {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
if (cause instanceof Error) {
|
|
1486
|
+
setCodeBlockError(cause.message || PARSE_FAILED);
|
|
1487
|
+
} else {
|
|
1488
|
+
setCodeBlockError(PARSE_FAILED);
|
|
1454
1489
|
}
|
|
1455
1490
|
}
|
|
1456
1491
|
};
|
|
@@ -2759,7 +2794,7 @@ const DropdownMenuTrigger$1 = DropdownMenuPrimitive.Trigger;
|
|
|
2759
2794
|
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
|
2760
2795
|
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
|
2761
2796
|
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
|
2762
|
-
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
2797
|
+
const DropdownMenuRadioGroup$1 = DropdownMenuPrimitive.RadioGroup;
|
|
2763
2798
|
const DropdownMenuSubTrigger = withRef(({ children, className, inset, ...props }, ref) => /* @__PURE__ */ React__default.createElement(
|
|
2764
2799
|
DropdownMenuPrimitive.SubTrigger,
|
|
2765
2800
|
{
|
|
@@ -2818,7 +2853,7 @@ const DropdownMenuCheckboxItem = withRef(({ children, className, ...props }, ref
|
|
|
2818
2853
|
/* @__PURE__ */ React__default.createElement("span", { className: "absolute left-2 flex size-3.5 items-center justify-center" }, /* @__PURE__ */ React__default.createElement(DropdownMenuPrimitive.ItemIndicator, null, /* @__PURE__ */ React__default.createElement(Icons.check, { className: "size-4" }))),
|
|
2819
2854
|
children
|
|
2820
2855
|
));
|
|
2821
|
-
const DropdownMenuRadioItem = withRef(({ children, className, hideIcon, ...props }, ref) => /* @__PURE__ */ React__default.createElement(
|
|
2856
|
+
const DropdownMenuRadioItem$1 = withRef(({ children, className, hideIcon, ...props }, ref) => /* @__PURE__ */ React__default.createElement(
|
|
2822
2857
|
DropdownMenuPrimitive.RadioItem,
|
|
2823
2858
|
{
|
|
2824
2859
|
className: cn$1(
|
|
@@ -2842,7 +2877,7 @@ const dropdownMenuLabelVariants = cva(
|
|
|
2842
2877
|
}
|
|
2843
2878
|
}
|
|
2844
2879
|
);
|
|
2845
|
-
const DropdownMenuLabel = withVariants(
|
|
2880
|
+
const DropdownMenuLabel$1 = withVariants(
|
|
2846
2881
|
DropdownMenuPrimitive.Label,
|
|
2847
2882
|
dropdownMenuLabelVariants,
|
|
2848
2883
|
["inset"]
|
|
@@ -4166,6 +4201,17 @@ TinaField.propTypes = {
|
|
|
4166
4201
|
Component: PropTypes.any.isRequired,
|
|
4167
4202
|
children: PropTypes.any
|
|
4168
4203
|
};
|
|
4204
|
+
const isErrorNamed = (error, name2) => error instanceof Error && error.name === name2;
|
|
4205
|
+
class SessionExpiredError extends Error {
|
|
4206
|
+
constructor() {
|
|
4207
|
+
super("Your session has ended. Please sign in again.");
|
|
4208
|
+
this.name = "SessionExpiredError";
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
const isSessionExpiredError = (error) => error instanceof SessionExpiredError || isErrorNamed(error, "SessionExpiredError");
|
|
4212
|
+
const dispatchSessionExpired = (events) => {
|
|
4213
|
+
events.dispatch({ type: "cms:session-expired" });
|
|
4214
|
+
};
|
|
4169
4215
|
const LoadingDots = ({
|
|
4170
4216
|
dotSize = 8,
|
|
4171
4217
|
color = "white"
|
|
@@ -4225,6 +4271,8 @@ const Button$2 = ({
|
|
|
4225
4271
|
medium: `text-sm h-10 px-8`,
|
|
4226
4272
|
custom: ``
|
|
4227
4273
|
};
|
|
4274
|
+
const isDisabled = disabled || busy;
|
|
4275
|
+
const inertProps = typeof Tag2 !== "string" || Tag2 === "button" ? { disabled: isDisabled } : isDisabled && { "aria-disabled": true, tabIndex: -1, href: void 0 };
|
|
4228
4276
|
return /* @__PURE__ */ React.createElement(
|
|
4229
4277
|
Tag2,
|
|
4230
4278
|
{
|
|
@@ -4236,7 +4284,9 @@ const Button$2 = ({
|
|
|
4236
4284
|
roundedClasses[rounded],
|
|
4237
4285
|
className
|
|
4238
4286
|
),
|
|
4239
|
-
...props
|
|
4287
|
+
...props,
|
|
4288
|
+
...inertProps,
|
|
4289
|
+
onClick: isDisabled ? void 0 : props.onClick
|
|
4240
4290
|
},
|
|
4241
4291
|
busy ? /* @__PURE__ */ React.createElement(LoadingDots, { color: "currentColor" }) : children
|
|
4242
4292
|
);
|
|
@@ -4279,7 +4329,8 @@ const IconButton = ({
|
|
|
4279
4329
|
stateClasses[state],
|
|
4280
4330
|
className
|
|
4281
4331
|
),
|
|
4282
|
-
...props
|
|
4332
|
+
...props,
|
|
4333
|
+
disabled: disabled || busy
|
|
4283
4334
|
},
|
|
4284
4335
|
children
|
|
4285
4336
|
);
|
|
@@ -4469,6 +4520,54 @@ function DropdownMenuItem({
|
|
|
4469
4520
|
}
|
|
4470
4521
|
);
|
|
4471
4522
|
}
|
|
4523
|
+
function DropdownMenuRadioGroup({
|
|
4524
|
+
...props
|
|
4525
|
+
}) {
|
|
4526
|
+
return /* @__PURE__ */ React.createElement(
|
|
4527
|
+
DropdownMenuPrimitive.RadioGroup,
|
|
4528
|
+
{
|
|
4529
|
+
"data-slot": "dropdown-menu-radio-group",
|
|
4530
|
+
...props
|
|
4531
|
+
}
|
|
4532
|
+
);
|
|
4533
|
+
}
|
|
4534
|
+
function DropdownMenuRadioItem({
|
|
4535
|
+
className,
|
|
4536
|
+
children,
|
|
4537
|
+
...props
|
|
4538
|
+
}) {
|
|
4539
|
+
return /* @__PURE__ */ React.createElement(
|
|
4540
|
+
DropdownMenuPrimitive.RadioItem,
|
|
4541
|
+
{
|
|
4542
|
+
"data-slot": "dropdown-menu-radio-item",
|
|
4543
|
+
className: cn(
|
|
4544
|
+
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
4545
|
+
className
|
|
4546
|
+
),
|
|
4547
|
+
...props
|
|
4548
|
+
},
|
|
4549
|
+
/* @__PURE__ */ React.createElement("span", { className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center" }, /* @__PURE__ */ React.createElement(DropdownMenuPrimitive.ItemIndicator, null, /* @__PURE__ */ React.createElement(CircleIcon, { className: "size-2 fill-current" }))),
|
|
4550
|
+
children
|
|
4551
|
+
);
|
|
4552
|
+
}
|
|
4553
|
+
function DropdownMenuLabel({
|
|
4554
|
+
className,
|
|
4555
|
+
inset,
|
|
4556
|
+
...props
|
|
4557
|
+
}) {
|
|
4558
|
+
return /* @__PURE__ */ React.createElement(
|
|
4559
|
+
DropdownMenuPrimitive.Label,
|
|
4560
|
+
{
|
|
4561
|
+
"data-slot": "dropdown-menu-label",
|
|
4562
|
+
"data-inset": inset,
|
|
4563
|
+
className: cn(
|
|
4564
|
+
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
|
|
4565
|
+
className
|
|
4566
|
+
),
|
|
4567
|
+
...props
|
|
4568
|
+
}
|
|
4569
|
+
);
|
|
4570
|
+
}
|
|
4472
4571
|
function DropdownMenuSeparator({
|
|
4473
4572
|
className,
|
|
4474
4573
|
...props
|
|
@@ -4698,6 +4797,56 @@ const SortableProvider = ({
|
|
|
4698
4797
|
}) => {
|
|
4699
4798
|
return /* @__PURE__ */ React__default.createElement(SortableContext, { items, strategy: verticalListSortingStrategy }, children);
|
|
4700
4799
|
};
|
|
4800
|
+
const formatDefaultBranchName = (filePath, crudType) => {
|
|
4801
|
+
let result = filePath;
|
|
4802
|
+
const contentPrefix = "content/";
|
|
4803
|
+
if (result.startsWith(contentPrefix)) {
|
|
4804
|
+
result = result.substring(contentPrefix.length);
|
|
4805
|
+
}
|
|
4806
|
+
const lastDot = result.lastIndexOf(".");
|
|
4807
|
+
const lastSlash = Math.max(result.lastIndexOf("/"), result.lastIndexOf("\\"));
|
|
4808
|
+
if (lastDot > lastSlash && lastDot > 0) {
|
|
4809
|
+
result = result.slice(0, lastDot);
|
|
4810
|
+
}
|
|
4811
|
+
result = normalizeBranchName(result);
|
|
4812
|
+
if (crudType === "delete") {
|
|
4813
|
+
result = `❌-${result}`;
|
|
4814
|
+
}
|
|
4815
|
+
return result;
|
|
4816
|
+
};
|
|
4817
|
+
const trimRefComponent = (part) => {
|
|
4818
|
+
let result = part.replace(/\.{2,}/g, ".");
|
|
4819
|
+
while (result.startsWith(".")) {
|
|
4820
|
+
result = result.slice(1);
|
|
4821
|
+
}
|
|
4822
|
+
let previous = "";
|
|
4823
|
+
while (previous !== result) {
|
|
4824
|
+
previous = result;
|
|
4825
|
+
if (result.endsWith(".lock")) {
|
|
4826
|
+
result = result.slice(0, -".lock".length);
|
|
4827
|
+
} else if (result.endsWith(".")) {
|
|
4828
|
+
result = result.slice(0, -1);
|
|
4829
|
+
}
|
|
4830
|
+
}
|
|
4831
|
+
return result;
|
|
4832
|
+
};
|
|
4833
|
+
const normalizeBranchName = (name2) => name2.replace(/[\x00-\x20\x7f~^:?*\[\\]+/g, "-").replace(/@\{/g, "-").split("/").map(trimRefComponent).filter(Boolean).join("/");
|
|
4834
|
+
function formatBranchName(str) {
|
|
4835
|
+
let result = "";
|
|
4836
|
+
let replacingInvalidChars = false;
|
|
4837
|
+
for (const char of str.toLowerCase()) {
|
|
4838
|
+
const code = char.charCodeAt(0);
|
|
4839
|
+
const isValid = char === "/" || char === "-" || char === "_" || code >= 48 && code <= 57 || code >= 97 && code <= 122;
|
|
4840
|
+
if (isValid) {
|
|
4841
|
+
result += char;
|
|
4842
|
+
replacingInvalidChars = false;
|
|
4843
|
+
} else if (!replacingInvalidChars) {
|
|
4844
|
+
result += "-";
|
|
4845
|
+
replacingInvalidChars = true;
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
return result;
|
|
4849
|
+
}
|
|
4701
4850
|
const textFieldClasses = "shadow-inner focus:shadow-outline focus:border-blue-500 focus:outline-none block text-base placeholder:text-gray-300 px-3 py-2 text-gray-600 w-full bg-white border border-gray-200 transition-all ease-out duration-150 focus:text-gray-900 rounded";
|
|
4702
4851
|
const disabledClasses$1 = "opacity-50 pointer-events-none cursor-not-allowed";
|
|
4703
4852
|
const BaseTextField = React.forwardRef(({ className, disabled, ...rest }, ref) => {
|
|
@@ -5502,12 +5651,38 @@ const dropzoneAcceptFromString = (str) => {
|
|
|
5502
5651
|
...(str || DEFAULT_MEDIA_UPLOAD_TYPES).split(",").map((x) => ({ [x]: [] }))
|
|
5503
5652
|
);
|
|
5504
5653
|
};
|
|
5505
|
-
const
|
|
5506
|
-
|
|
5507
|
-
};
|
|
5508
|
-
const
|
|
5509
|
-
|
|
5654
|
+
const dropzoneAcceptFromExtensions = (extensions) => {
|
|
5655
|
+
if (!extensions.length) return void 0;
|
|
5656
|
+
const accept = {};
|
|
5657
|
+
for (const ext of extensions) {
|
|
5658
|
+
const mimeType = MEDIA_MIME_TYPES[ext];
|
|
5659
|
+
accept[mimeType] ?? (accept[mimeType] = []);
|
|
5660
|
+
accept[mimeType].push(`.${ext}`);
|
|
5661
|
+
}
|
|
5662
|
+
return accept;
|
|
5510
5663
|
};
|
|
5664
|
+
const PREVIEWABLE_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5665
|
+
"gif",
|
|
5666
|
+
"jpg",
|
|
5667
|
+
"jpeg",
|
|
5668
|
+
"tiff",
|
|
5669
|
+
"png",
|
|
5670
|
+
"svg",
|
|
5671
|
+
"webp",
|
|
5672
|
+
"avif"
|
|
5673
|
+
]);
|
|
5674
|
+
const PREVIEWABLE_VIDEO_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
5675
|
+
"mp4",
|
|
5676
|
+
"webm",
|
|
5677
|
+
"ogg",
|
|
5678
|
+
"m4v",
|
|
5679
|
+
"mov",
|
|
5680
|
+
"avi",
|
|
5681
|
+
"flv",
|
|
5682
|
+
"mkv"
|
|
5683
|
+
]);
|
|
5684
|
+
const isImage = (filename) => PREVIEWABLE_IMAGE_EXTENSIONS.has(extensionOf(filename ?? ""));
|
|
5685
|
+
const isVideo = (filename) => PREVIEWABLE_VIDEO_EXTENSIONS.has(extensionOf(filename ?? ""));
|
|
5511
5686
|
const absoluteImgURL = (str) => {
|
|
5512
5687
|
if (str.startsWith("http")) return str;
|
|
5513
5688
|
return `${window.location.origin}${str}`;
|
|
@@ -5569,12 +5744,13 @@ const StyledImage = ({ src }) => {
|
|
|
5569
5744
|
const StyledFile = ({ src }) => {
|
|
5570
5745
|
return /* @__PURE__ */ React.createElement("div", { className: "max-w-full w-full flex-1 flex justify-start items-center gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "w-12 h-12 bg-white shadow border border-gray-100 rounded flex justify-center flex-none" }, /* @__PURE__ */ React.createElement(File$1, { className: "w-3/5 h-full text-gray-300" })), /* @__PURE__ */ React.createElement("span", { className: "text-base text-left flex-1 text-gray-500 w-full break-words truncate" }, src));
|
|
5571
5746
|
};
|
|
5572
|
-
const ImageUpload = React.forwardRef(({ onDrop, onClear, onClick, value, src, loading }, ref) => {
|
|
5747
|
+
const ImageUpload = React.forwardRef(({ onDrop, onClear, onClick, value, src, loading, accept }, ref) => {
|
|
5573
5748
|
const cms = useCMS();
|
|
5574
5749
|
const { getRootProps, getInputProps } = useDropzone$1({
|
|
5575
|
-
accept
|
|
5576
|
-
|
|
5577
|
-
|
|
5750
|
+
// A field's `accept` overrides the global `media.accept`, so a file the
|
|
5751
|
+
// field would refuse is rejected here rather than uploaded and then
|
|
5752
|
+
// discarded by the insert guard.
|
|
5753
|
+
accept: dropzoneAcceptFromExtensions(resolveMediaAccept(accept)) ?? dropzoneAcceptFromString(cms.media.accept || DEFAULT_MEDIA_UPLOAD_TYPES),
|
|
5578
5754
|
onDrop,
|
|
5579
5755
|
noClick: !!onClick
|
|
5580
5756
|
});
|
|
@@ -6193,6 +6369,7 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6193
6369
|
return /* @__PURE__ */ React__default.createElement(
|
|
6194
6370
|
ListFieldMeta,
|
|
6195
6371
|
{
|
|
6372
|
+
"data-test": `list-${field.name}`,
|
|
6196
6373
|
name: input.name,
|
|
6197
6374
|
label: field.label,
|
|
6198
6375
|
description: field.description,
|
|
@@ -6203,6 +6380,7 @@ const Group$1 = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
6203
6380
|
actions: (!fixedLength || fixedLength && !isMax) && /* @__PURE__ */ React__default.createElement(
|
|
6204
6381
|
IconButton,
|
|
6205
6382
|
{
|
|
6383
|
+
"data-test": `add-item-${field.name}`,
|
|
6206
6384
|
onClick: addItem,
|
|
6207
6385
|
disabled: isMax,
|
|
6208
6386
|
variant: "primary",
|
|
@@ -6295,7 +6473,14 @@ const Item$1 = ({
|
|
|
6295
6473
|
/* @__PURE__ */ React__default.createElement(GroupLabel, null, title),
|
|
6296
6474
|
/* @__PURE__ */ React__default.createElement(Pencil, { className: "h-5 w-auto text-gray-200 group-hover:text-inherit transition-colors duration-150 ease-out" })
|
|
6297
6475
|
),
|
|
6298
|
-
(!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React__default.createElement(
|
|
6476
|
+
(!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React__default.createElement(
|
|
6477
|
+
ItemDeleteButton,
|
|
6478
|
+
{
|
|
6479
|
+
disabled: isMin,
|
|
6480
|
+
onClick: removeItem,
|
|
6481
|
+
fieldName: `${field.name}.${index}`
|
|
6482
|
+
}
|
|
6483
|
+
)
|
|
6299
6484
|
)));
|
|
6300
6485
|
};
|
|
6301
6486
|
const ItemClickTarget = ({ children, ...props }) => {
|
|
@@ -6342,11 +6527,16 @@ const ItemHeader = ({
|
|
|
6342
6527
|
children
|
|
6343
6528
|
);
|
|
6344
6529
|
};
|
|
6345
|
-
const ItemDeleteButton = ({
|
|
6530
|
+
const ItemDeleteButton = ({
|
|
6531
|
+
onClick,
|
|
6532
|
+
disabled = false,
|
|
6533
|
+
fieldName = ""
|
|
6534
|
+
}) => {
|
|
6346
6535
|
return /* @__PURE__ */ React__default.createElement(
|
|
6347
6536
|
"button",
|
|
6348
6537
|
{
|
|
6349
6538
|
type: "button",
|
|
6539
|
+
"data-test": fieldName ? `delete-item-${fieldName}` : "delete-item",
|
|
6350
6540
|
className: `w-8 px-1 py-2.5 flex items-center justify-center text-gray-200 hover:opacity-100 opacity-30 hover:bg-gray-50 ${disabled && "pointer-events-none opacity-30 cursor-not-allowed"}`,
|
|
6351
6541
|
onClick
|
|
6352
6542
|
},
|
|
@@ -6389,7 +6579,8 @@ const PopoverContent = React.forwardRef(({ className, align = "center", sideOffs
|
|
|
6389
6579
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
6390
6580
|
const BlockSelector = ({
|
|
6391
6581
|
templates,
|
|
6392
|
-
addItem
|
|
6582
|
+
addItem,
|
|
6583
|
+
fieldName
|
|
6393
6584
|
}) => {
|
|
6394
6585
|
const showFilter = React.useMemo(() => {
|
|
6395
6586
|
return Object.entries(templates).length > 6;
|
|
@@ -6404,6 +6595,7 @@ const BlockSelector = ({
|
|
|
6404
6595
|
return /* @__PURE__ */ React.createElement(Popover, { open, onOpenChange: setOpen }, /* @__PURE__ */ React.createElement(PopoverTrigger, { asChild: true }, /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement(
|
|
6405
6596
|
IconButton,
|
|
6406
6597
|
{
|
|
6598
|
+
"data-test": fieldName ? `add-item-${fieldName}` : void 0,
|
|
6407
6599
|
variant: open ? "secondary" : "primary",
|
|
6408
6600
|
size: "small",
|
|
6409
6601
|
className: `${open ? `rotate-45 pointer-events-none` : ``}`
|
|
@@ -6703,7 +6895,8 @@ const constructUrlWithBasePath = (url, basePath) => {
|
|
|
6703
6895
|
const BlockSelectorBig = ({
|
|
6704
6896
|
templates,
|
|
6705
6897
|
addItem,
|
|
6706
|
-
label
|
|
6898
|
+
label,
|
|
6899
|
+
fieldName
|
|
6707
6900
|
}) => {
|
|
6708
6901
|
const FormPortal = useFormPortal();
|
|
6709
6902
|
const [pickerIsOpen, setPickerIsOpen] = React.useState(false);
|
|
@@ -6748,6 +6941,7 @@ const BlockSelectorBig = ({
|
|
|
6748
6941
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
6749
6942
|
IconButton,
|
|
6750
6943
|
{
|
|
6944
|
+
"data-test": fieldName ? `add-item-${fieldName}` : void 0,
|
|
6751
6945
|
variant: pickerIsOpen ? "secondary" : "primary",
|
|
6752
6946
|
size: "small",
|
|
6753
6947
|
className: `${pickerIsOpen ? "rotate-45 pointer-events-none" : ""}`,
|
|
@@ -6962,6 +7156,7 @@ const Blocks = ({
|
|
|
6962
7156
|
return /* @__PURE__ */ React.createElement(
|
|
6963
7157
|
ListFieldMeta,
|
|
6964
7158
|
{
|
|
7159
|
+
"data-test": `list-${field.name}`,
|
|
6965
7160
|
name: input.name,
|
|
6966
7161
|
label: field.label,
|
|
6967
7162
|
description: field.description,
|
|
@@ -6970,9 +7165,17 @@ const Blocks = ({
|
|
|
6970
7165
|
index,
|
|
6971
7166
|
tinaForm,
|
|
6972
7167
|
actions: (!fixedLength || fixedLength && !isMax) && // @ts-ignore
|
|
6973
|
-
(!field.visualSelector ? /* @__PURE__ */ React.createElement(
|
|
7168
|
+
(!field.visualSelector ? /* @__PURE__ */ React.createElement(
|
|
7169
|
+
BlockSelector,
|
|
7170
|
+
{
|
|
7171
|
+
templates: field.templates,
|
|
7172
|
+
addItem,
|
|
7173
|
+
fieldName: field.name
|
|
7174
|
+
}
|
|
7175
|
+
) : /* @__PURE__ */ React.createElement(
|
|
6974
7176
|
BlockSelectorBig,
|
|
6975
7177
|
{
|
|
7178
|
+
fieldName: field.name,
|
|
6976
7179
|
label: field.label || field.name,
|
|
6977
7180
|
templates: field.templates,
|
|
6978
7181
|
addItem
|
|
@@ -7074,7 +7277,14 @@ const BlockListItem = ({
|
|
|
7074
7277
|
/* @__PURE__ */ React.createElement(GroupLabel, null, label || template.label),
|
|
7075
7278
|
isNew && /* @__PURE__ */ React.createElement("span", { className: "mr-1.5 inline-flex items-center px-1.5 py-0.5 rounded text-[10px] border-[0.5px] border-tina-orange/50 font-semibold bg-tina-orange/10 text-tina-orange leading-none" }, "NEW"),
|
|
7076
7279
|
/* @__PURE__ */ React.createElement(Pencil, { className: "h-5 w-auto text-gray-200 group-hover:text-inherit transition-colors duration-150 ease-out" })
|
|
7077
|
-
), (!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React.createElement(
|
|
7280
|
+
), (!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React.createElement(
|
|
7281
|
+
ItemDeleteButton,
|
|
7282
|
+
{
|
|
7283
|
+
disabled: isMin,
|
|
7284
|
+
onClick: removeItem,
|
|
7285
|
+
fieldName: `${field.name}.${index}`
|
|
7286
|
+
}
|
|
7287
|
+
))));
|
|
7078
7288
|
};
|
|
7079
7289
|
const InvalidBlockListItem = ({
|
|
7080
7290
|
tinaForm,
|
|
@@ -7090,7 +7300,13 @@ const InvalidBlockListItem = ({
|
|
|
7090
7300
|
isDragging: snapshot.isDragging,
|
|
7091
7301
|
dragHandleProps: provider.dragHandleProps
|
|
7092
7302
|
}
|
|
7093
|
-
), /* @__PURE__ */ React.createElement(ItemClickTarget, null, /* @__PURE__ */ React.createElement(GroupLabel, { error: true }, "Invalid Block")), /* @__PURE__ */ React.createElement(
|
|
7303
|
+
), /* @__PURE__ */ React.createElement(ItemClickTarget, null, /* @__PURE__ */ React.createElement(GroupLabel, { error: true }, "Invalid Block")), /* @__PURE__ */ React.createElement(
|
|
7304
|
+
ItemDeleteButton,
|
|
7305
|
+
{
|
|
7306
|
+
onClick: removeItem,
|
|
7307
|
+
fieldName: `${field.name}.${index}`
|
|
7308
|
+
}
|
|
7309
|
+
)));
|
|
7094
7310
|
};
|
|
7095
7311
|
const BlocksField = Blocks;
|
|
7096
7312
|
const BlocksFieldPlugin = {
|
|
@@ -7148,6 +7364,7 @@ const List = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
7148
7364
|
return /* @__PURE__ */ React.createElement(
|
|
7149
7365
|
ListFieldMeta,
|
|
7150
7366
|
{
|
|
7367
|
+
"data-test": `list-${field.name}`,
|
|
7151
7368
|
name: input.name,
|
|
7152
7369
|
label: field.label,
|
|
7153
7370
|
description: field.description,
|
|
@@ -7157,6 +7374,7 @@ const List = ({ tinaForm, form, field, input, meta, index }) => {
|
|
|
7157
7374
|
actions: /* @__PURE__ */ React.createElement(
|
|
7158
7375
|
IconButton,
|
|
7159
7376
|
{
|
|
7377
|
+
"data-test": `add-item-${field.name}`,
|
|
7160
7378
|
onClick: addItem,
|
|
7161
7379
|
variant: "primary",
|
|
7162
7380
|
size: "small",
|
|
@@ -7215,7 +7433,14 @@ const Item = ({
|
|
|
7215
7433
|
isDragging: snapshot.isDragging,
|
|
7216
7434
|
dragHandleProps: provider.dragHandleProps
|
|
7217
7435
|
}
|
|
7218
|
-
), /* @__PURE__ */ React.createElement(ItemClickTarget, null, /* @__PURE__ */ React.createElement(FieldsBuilder, { padding: false, form: tinaForm, fields })), (!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React.createElement(
|
|
7436
|
+
), /* @__PURE__ */ React.createElement(ItemClickTarget, null, /* @__PURE__ */ React.createElement(FieldsBuilder, { padding: false, form: tinaForm, fields })), (!fixedLength || fixedLength && !isMin) && /* @__PURE__ */ React.createElement(
|
|
7437
|
+
ItemDeleteButton,
|
|
7438
|
+
{
|
|
7439
|
+
disabled: isMin,
|
|
7440
|
+
onClick: removeItem,
|
|
7441
|
+
fieldName: `${field.name}.${index}`
|
|
7442
|
+
}
|
|
7443
|
+
)));
|
|
7219
7444
|
};
|
|
7220
7445
|
const ListField = List;
|
|
7221
7446
|
const ListFieldPlugin = {
|
|
@@ -7245,6 +7470,16 @@ const ImageField = wrapFieldsWithMeta(
|
|
|
7245
7470
|
var _a, _b;
|
|
7246
7471
|
if (media) {
|
|
7247
7472
|
const item = Array.isArray(media) ? media[0] : media;
|
|
7473
|
+
const allowed = resolveMediaAccept(
|
|
7474
|
+
props.field.accept
|
|
7475
|
+
);
|
|
7476
|
+
const ext = extensionOf(item.filename) || extensionOf(item.src ?? "");
|
|
7477
|
+
if (allowed.length && !allowed.includes(ext)) {
|
|
7478
|
+
cms.alerts.error(
|
|
7479
|
+
`${item.filename} is not an accepted file type. This field accepts ${allowed.join(", ")}.`
|
|
7480
|
+
);
|
|
7481
|
+
return;
|
|
7482
|
+
}
|
|
7248
7483
|
const parsedValue = typeof ((_b = (_a = cms == null ? void 0 : cms.media) == null ? void 0 : _a.store) == null ? void 0 : _b.parse) === "function" ? cms.media.store.parse(item) : item.src || item;
|
|
7249
7484
|
props.input.onChange(parsedValue);
|
|
7250
7485
|
}
|
|
@@ -7257,12 +7492,14 @@ const ImageField = wrapFieldsWithMeta(
|
|
|
7257
7492
|
value,
|
|
7258
7493
|
src,
|
|
7259
7494
|
loading: isImgUploading,
|
|
7495
|
+
accept: props.field.accept,
|
|
7260
7496
|
onClick: () => {
|
|
7261
7497
|
const directory = uploadDir(props.form.getState().values);
|
|
7262
7498
|
cms.media.open({
|
|
7263
7499
|
allowDelete: true,
|
|
7264
7500
|
directory,
|
|
7265
|
-
onSelect: onChange
|
|
7501
|
+
onSelect: onChange,
|
|
7502
|
+
accept: props.field.accept
|
|
7266
7503
|
});
|
|
7267
7504
|
},
|
|
7268
7505
|
onDrop: async ([file], fileRejections) => {
|
|
@@ -8647,6 +8884,34 @@ const InfoBox = ({
|
|
|
8647
8884
|
InfoBoxComponent.displayName = "InfoBox";
|
|
8648
8885
|
return InfoBoxComponent;
|
|
8649
8886
|
};
|
|
8887
|
+
function useLocalStorage(key, initialValue) {
|
|
8888
|
+
const [storedValue, setStoredValue] = React.useState(() => {
|
|
8889
|
+
try {
|
|
8890
|
+
const valueFromStorage = typeof window !== "undefined" && window.localStorage && window.localStorage.getItem(key);
|
|
8891
|
+
if (valueFromStorage != null) {
|
|
8892
|
+
return JSON.parse(valueFromStorage);
|
|
8893
|
+
}
|
|
8894
|
+
} catch (error) {
|
|
8895
|
+
}
|
|
8896
|
+
return initialValue;
|
|
8897
|
+
});
|
|
8898
|
+
React.useEffect(() => {
|
|
8899
|
+
const valueFromStorage = window.localStorage && window.localStorage.getItem(key);
|
|
8900
|
+
if (valueFromStorage != null && valueFromStorage != void 0) {
|
|
8901
|
+
setStoredValue(JSON.parse(valueFromStorage));
|
|
8902
|
+
}
|
|
8903
|
+
}, [key]);
|
|
8904
|
+
const setValue = (value) => {
|
|
8905
|
+
try {
|
|
8906
|
+
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
8907
|
+
setStoredValue(valueToStore);
|
|
8908
|
+
localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
8909
|
+
} catch (error) {
|
|
8910
|
+
console.log(error);
|
|
8911
|
+
}
|
|
8912
|
+
};
|
|
8913
|
+
return [storedValue, setValue];
|
|
8914
|
+
}
|
|
8650
8915
|
const Badge = ({
|
|
8651
8916
|
children,
|
|
8652
8917
|
calloutStyle = "warning",
|
|
@@ -8708,11 +8973,6 @@ const useBranchData = () => {
|
|
|
8708
8973
|
}, [branchData.currentBranch]);
|
|
8709
8974
|
return branchData;
|
|
8710
8975
|
};
|
|
8711
|
-
function formatBranchName$1(str) {
|
|
8712
|
-
const pattern = /[^/\w-]+/g;
|
|
8713
|
-
const formattedStr = str.replace(pattern, "");
|
|
8714
|
-
return formattedStr.toLowerCase();
|
|
8715
|
-
}
|
|
8716
8976
|
const BranchSwitcherLegacy = ({
|
|
8717
8977
|
listBranches,
|
|
8718
8978
|
createBranch,
|
|
@@ -8735,7 +8995,7 @@ const BranchSwitcherLegacy = ({
|
|
|
8735
8995
|
const handleCreateBranch = React.useCallback((value) => {
|
|
8736
8996
|
setListState("loading");
|
|
8737
8997
|
createBranch({
|
|
8738
|
-
branchName: formatBranchName
|
|
8998
|
+
branchName: normalizeBranchName(formatBranchName(value)),
|
|
8739
8999
|
baseBranch: currentBranch
|
|
8740
9000
|
}).then(async (createdBranchName) => {
|
|
8741
9001
|
cms.alerts.success("Branch created.");
|
|
@@ -8905,6 +9165,9 @@ const BranchSelector = ({
|
|
|
8905
9165
|
));
|
|
8906
9166
|
};
|
|
8907
9167
|
const CreateBranch = ({ currentBranch, newBranchName, onCreateBranch, setNewBranchName }) => {
|
|
9168
|
+
const normalizedBranchName = normalizeBranchName(
|
|
9169
|
+
formatBranchName(newBranchName)
|
|
9170
|
+
);
|
|
8908
9171
|
return /* @__PURE__ */ React.createElement("div", { className: "border-t border-gray-150 pt-4 mt-3 flex flex-col gap-3" }, /* @__PURE__ */ React.createElement("div", { className: "text-sm" }, "Create a new branch from ", /* @__PURE__ */ React.createElement("b", null, currentBranch), ". Once created you will need to wait for indexing to complete before you can switch branches."), /* @__PURE__ */ React.createElement("div", { className: "flex justify-between items-center w-full gap-3" }, /* @__PURE__ */ React.createElement(
|
|
8909
9172
|
BaseTextField,
|
|
8910
9173
|
{
|
|
@@ -8918,8 +9181,11 @@ const CreateBranch = ({ currentBranch, newBranchName, onCreateBranch, setNewBran
|
|
|
8918
9181
|
className: "flex-0 flex items-center gap-2 whitespace-nowrap",
|
|
8919
9182
|
size: "medium",
|
|
8920
9183
|
variant: "white",
|
|
8921
|
-
disabled:
|
|
8922
|
-
onClick: () =>
|
|
9184
|
+
disabled: normalizedBranchName === "",
|
|
9185
|
+
onClick: () => {
|
|
9186
|
+
if (!normalizedBranchName) return;
|
|
9187
|
+
onCreateBranch(normalizedBranchName);
|
|
9188
|
+
}
|
|
8923
9189
|
},
|
|
8924
9190
|
/* @__PURE__ */ React.createElement(Plus, { className: "w-5 h-auto opacity-70" }),
|
|
8925
9191
|
" Create Branch"
|
|
@@ -9373,22 +9639,6 @@ const PullRequestCell = ({
|
|
|
9373
9639
|
}
|
|
9374
9640
|
return null;
|
|
9375
9641
|
};
|
|
9376
|
-
function formatBranchName(str) {
|
|
9377
|
-
let result = "";
|
|
9378
|
-
let replacingInvalidChars = false;
|
|
9379
|
-
for (const char of str.toLowerCase()) {
|
|
9380
|
-
const code = char.charCodeAt(0);
|
|
9381
|
-
const isValid = char === "/" || char === "-" || char === "_" || code >= 48 && code <= 57 || code >= 97 && code <= 122;
|
|
9382
|
-
if (isValid) {
|
|
9383
|
-
result += char;
|
|
9384
|
-
replacingInvalidChars = false;
|
|
9385
|
-
} else if (!replacingInvalidChars) {
|
|
9386
|
-
result += "-";
|
|
9387
|
-
replacingInvalidChars = true;
|
|
9388
|
-
}
|
|
9389
|
-
}
|
|
9390
|
-
return result;
|
|
9391
|
-
}
|
|
9392
9642
|
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 ";
|
|
9393
9643
|
const BranchSwitcher = (props) => {
|
|
9394
9644
|
const cms = useCMS$1();
|
|
@@ -9429,7 +9679,7 @@ const EditoralBranchSwitcher = ({
|
|
|
9429
9679
|
const handleCreateBranch = React.useCallback((value) => {
|
|
9430
9680
|
setListState("loading");
|
|
9431
9681
|
createBranch({
|
|
9432
|
-
branchName: formatBranchName(value),
|
|
9682
|
+
branchName: normalizeBranchName(formatBranchName(value)),
|
|
9433
9683
|
baseBranch: currentBranch
|
|
9434
9684
|
}).then(async (createdBranchName) => {
|
|
9435
9685
|
cms.alerts.success("Branch created.");
|
|
@@ -9573,46 +9823,58 @@ const sortBranchListFn = (sortValue) => {
|
|
|
9573
9823
|
}
|
|
9574
9824
|
};
|
|
9575
9825
|
};
|
|
9576
|
-
const BranchCreator = ({
|
|
9826
|
+
const BranchCreator = ({
|
|
9827
|
+
setViewState,
|
|
9828
|
+
handleCreateBranch,
|
|
9829
|
+
currentBranch
|
|
9830
|
+
}) => {
|
|
9577
9831
|
const [branchName, setBranchName] = React.useState("");
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
9584
|
-
}
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
9588
|
-
|
|
9589
|
-
|
|
9590
|
-
value: branchName,
|
|
9591
|
-
onChange: (e) => setBranchName(e.target.value)
|
|
9592
|
-
}
|
|
9593
|
-
))), /* @__PURE__ */ React.createElement("div", { className: "w-full flex justify-between gap-4 items-center" }, /* @__PURE__ */ React.createElement(
|
|
9594
|
-
Button$2,
|
|
9595
|
-
{
|
|
9596
|
-
style: { flexGrow: 1 },
|
|
9597
|
-
onClick: () => {
|
|
9598
|
-
setViewState("list");
|
|
9832
|
+
const normalizedBranchName = normalizeBranchName(
|
|
9833
|
+
formatBranchName(branchName)
|
|
9834
|
+
);
|
|
9835
|
+
return (
|
|
9836
|
+
// Submit is handled by the button below; without this the implicit
|
|
9837
|
+
// submission from pressing Enter in the field reloads the page
|
|
9838
|
+
/* @__PURE__ */ React.createElement("form", { onSubmit: (e) => e.preventDefault() }, /* @__PURE__ */ React.createElement("div", { className: "" }, /* @__PURE__ */ React.createElement("p", { className: "text-base text-gray-700 mb-4" }, "Create a new branch from ", /* @__PURE__ */ React.createElement("strong", null, currentBranch), "."), /* @__PURE__ */ React.createElement("div", { className: "mb-3" }, /* @__PURE__ */ React.createElement(FieldLabel, { name: "current-branch-name" }, "Current Branch Name"), /* @__PURE__ */ React.createElement(
|
|
9839
|
+
BaseTextField,
|
|
9840
|
+
{
|
|
9841
|
+
name: "current-branch-name",
|
|
9842
|
+
value: currentBranch,
|
|
9843
|
+
disabled: true
|
|
9599
9844
|
}
|
|
9600
|
-
},
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
style: { flexGrow: 2 },
|
|
9608
|
-
disabled: branchName === "",
|
|
9609
|
-
onClick: () => {
|
|
9610
|
-
handleCreateBranch("tina/" + branchName);
|
|
9845
|
+
)), /* @__PURE__ */ React.createElement("div", { className: "mb-6" }, /* @__PURE__ */ React.createElement(FieldLabel, { name: "branch-name" }, "New Branch Name"), /* @__PURE__ */ React.createElement(
|
|
9846
|
+
PrefixedTextField,
|
|
9847
|
+
{
|
|
9848
|
+
placeholder: "",
|
|
9849
|
+
name: "branch-name",
|
|
9850
|
+
value: branchName,
|
|
9851
|
+
onChange: (e) => setBranchName(e.target.value)
|
|
9611
9852
|
}
|
|
9612
|
-
},
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9853
|
+
))), /* @__PURE__ */ React.createElement("div", { className: "w-full flex justify-between gap-4 items-center" }, /* @__PURE__ */ React.createElement(
|
|
9854
|
+
Button$2,
|
|
9855
|
+
{
|
|
9856
|
+
style: { flexGrow: 1 },
|
|
9857
|
+
onClick: () => {
|
|
9858
|
+
setViewState("list");
|
|
9859
|
+
}
|
|
9860
|
+
},
|
|
9861
|
+
"Cancel"
|
|
9862
|
+
), /* @__PURE__ */ React.createElement(
|
|
9863
|
+
Button$2,
|
|
9864
|
+
{
|
|
9865
|
+
variant: "primary",
|
|
9866
|
+
type: "submit",
|
|
9867
|
+
style: { flexGrow: 2 },
|
|
9868
|
+
disabled: normalizedBranchName === "",
|
|
9869
|
+
onClick: () => {
|
|
9870
|
+
if (!normalizedBranchName) return;
|
|
9871
|
+
handleCreateBranch("tina/" + normalizedBranchName);
|
|
9872
|
+
}
|
|
9873
|
+
},
|
|
9874
|
+
"Create Branch ",
|
|
9875
|
+
/* @__PURE__ */ React.createElement(GitBranch, { className: "w-5 h-full ml-1 opacity-70" })
|
|
9876
|
+
)))
|
|
9877
|
+
);
|
|
9616
9878
|
};
|
|
9617
9879
|
const extractPullRequestId = (url) => {
|
|
9618
9880
|
return url.split("/").pop() || "";
|
|
@@ -9809,9 +10071,21 @@ let Alerts$1 = class Alerts {
|
|
|
9809
10071
|
this.add(level, message, timeout);
|
|
9810
10072
|
}
|
|
9811
10073
|
});
|
|
10074
|
+
/**
|
|
10075
|
+
* While suppressed (the window between a session expiring and the user
|
|
10076
|
+
* signing back in), new alerts are dropped so nothing paints over the
|
|
10077
|
+
* login modal. Alerts already showing are left alone.
|
|
10078
|
+
*/
|
|
10079
|
+
__publicField(this, "suppressed", false);
|
|
9812
10080
|
this.events = events;
|
|
9813
10081
|
this.map = map;
|
|
9814
10082
|
this.events.subscribe("*", this.mapEventToAlert);
|
|
10083
|
+
this.events.subscribe("cms:session-expired", () => {
|
|
10084
|
+
this.suppressed = true;
|
|
10085
|
+
});
|
|
10086
|
+
this.events.subscribe("cms:login", () => {
|
|
10087
|
+
this.suppressed = false;
|
|
10088
|
+
});
|
|
9815
10089
|
}
|
|
9816
10090
|
setMap(eventsToAlerts) {
|
|
9817
10091
|
this.map = {
|
|
@@ -9820,6 +10094,10 @@ let Alerts$1 = class Alerts {
|
|
|
9820
10094
|
};
|
|
9821
10095
|
}
|
|
9822
10096
|
add(level, message, timeout = 4e3) {
|
|
10097
|
+
if (this.suppressed) {
|
|
10098
|
+
return () => {
|
|
10099
|
+
};
|
|
10100
|
+
}
|
|
9823
10101
|
const alert = {
|
|
9824
10102
|
level,
|
|
9825
10103
|
message,
|
|
@@ -9860,219 +10138,6 @@ let Alerts$1 = class Alerts {
|
|
|
9860
10138
|
return this.add("error", message, timeout);
|
|
9861
10139
|
}
|
|
9862
10140
|
};
|
|
9863
|
-
class PluginTypeManager {
|
|
9864
|
-
constructor(events) {
|
|
9865
|
-
/**
|
|
9866
|
-
* @ignore
|
|
9867
|
-
*/
|
|
9868
|
-
__publicField(this, "plugins", {});
|
|
9869
|
-
this.events = events;
|
|
9870
|
-
}
|
|
9871
|
-
/**
|
|
9872
|
-
* Gets the [[PluginType|collection of plugins]] for the given type.
|
|
9873
|
-
*
|
|
9874
|
-
* #### Example: Basic Usage
|
|
9875
|
-
*
|
|
9876
|
-
* ```ts
|
|
9877
|
-
* const colorPlugins = cms.plugins.get("color")
|
|
9878
|
-
* ```
|
|
9879
|
-
*
|
|
9880
|
-
* #### Example: Advanced Types
|
|
9881
|
-
*
|
|
9882
|
-
* A type param can be added to specify the kind of Plugin
|
|
9883
|
-
* that is being listed.
|
|
9884
|
-
*
|
|
9885
|
-
* ```ts
|
|
9886
|
-
* const colorPlugins = cms.plugins.get<ColorPlugin>("color")
|
|
9887
|
-
* ```
|
|
9888
|
-
*
|
|
9889
|
-
* @param type The type of plugins to be retrieved
|
|
9890
|
-
* @typeparam P A subclass of Plugin. Optional.
|
|
9891
|
-
*/
|
|
9892
|
-
getType(type2) {
|
|
9893
|
-
return this.plugins[type2] = this.plugins[type2] || new PluginType(type2, this.events);
|
|
9894
|
-
}
|
|
9895
|
-
/**
|
|
9896
|
-
* An alias to [[get]]
|
|
9897
|
-
*
|
|
9898
|
-
* ### !DEPRECATED!
|
|
9899
|
-
*
|
|
9900
|
-
* This name is unnecessarily verbose and weird.
|
|
9901
|
-
*/
|
|
9902
|
-
findOrCreateMap(type2) {
|
|
9903
|
-
return this.getType(type2);
|
|
9904
|
-
}
|
|
9905
|
-
/**
|
|
9906
|
-
* Adds a Plugin to the CMS.
|
|
9907
|
-
*
|
|
9908
|
-
* #### Example: Basic Usage
|
|
9909
|
-
*
|
|
9910
|
-
* ```js
|
|
9911
|
-
* cms.plugins.add({ __type: "color", name: "red" })
|
|
9912
|
-
* ```
|
|
9913
|
-
*
|
|
9914
|
-
* #### Example: Advanced Types
|
|
9915
|
-
*
|
|
9916
|
-
* ```ts
|
|
9917
|
-
* interface ColorPlugin extends Plugin {
|
|
9918
|
-
* __type: "color"
|
|
9919
|
-
* hex: string
|
|
9920
|
-
* rgb: string
|
|
9921
|
-
* }
|
|
9922
|
-
*
|
|
9923
|
-
* cms.plugins.add<ColorPlugin>({
|
|
9924
|
-
* __type: "color",
|
|
9925
|
-
* name: "red",
|
|
9926
|
-
* hex: "#FF0000",
|
|
9927
|
-
* rgb: "RGBA(255, 0, 0, 1)"
|
|
9928
|
-
* })
|
|
9929
|
-
* ```
|
|
9930
|
-
*
|
|
9931
|
-
* @typeparam P A subclass of Plugin. Optional.
|
|
9932
|
-
* @param plugin
|
|
9933
|
-
* @todo Consider returning the plugin which was just added.
|
|
9934
|
-
*/
|
|
9935
|
-
add(plugin) {
|
|
9936
|
-
this.findOrCreateMap(plugin.__type).add(plugin);
|
|
9937
|
-
}
|
|
9938
|
-
/**
|
|
9939
|
-
* Removes the given plugin from the CMS.
|
|
9940
|
-
*
|
|
9941
|
-
* #### Example
|
|
9942
|
-
*
|
|
9943
|
-
* In this example a plugin is added to the CMS and removed
|
|
9944
|
-
* 5 seconds later.
|
|
9945
|
-
*
|
|
9946
|
-
* ```ts
|
|
9947
|
-
* const redPlugin = {
|
|
9948
|
-
* __type: "color",
|
|
9949
|
-
* name: "red",
|
|
9950
|
-
* hex: "#FF0000",
|
|
9951
|
-
* rgb: "RGBA(255, 0, 0, 1)"
|
|
9952
|
-
* }
|
|
9953
|
-
*
|
|
9954
|
-
* cms.plugins.add(redPlugin)
|
|
9955
|
-
*
|
|
9956
|
-
* setTimeout(() => {
|
|
9957
|
-
* cms.plugins.remove(redPlugin)
|
|
9958
|
-
* }, 5000)
|
|
9959
|
-
* ```
|
|
9960
|
-
*
|
|
9961
|
-
* @typeparam P A subclass of Plugin. Optional.
|
|
9962
|
-
* @param plugin The plugin to be removed from the CMS.
|
|
9963
|
-
*/
|
|
9964
|
-
remove(plugin) {
|
|
9965
|
-
this.findOrCreateMap(plugin.__type).remove(plugin);
|
|
9966
|
-
}
|
|
9967
|
-
/**
|
|
9968
|
-
* Returns a list of all the plugins of the given type.
|
|
9969
|
-
*
|
|
9970
|
-
* #### Example: Basic Usage
|
|
9971
|
-
*
|
|
9972
|
-
* ```ts
|
|
9973
|
-
* cms.plugins.all("color").forEach(color => {
|
|
9974
|
-
* console.log(color.name)
|
|
9975
|
-
* })
|
|
9976
|
-
* ```
|
|
9977
|
-
*
|
|
9978
|
-
* #### Example: Advanced Types
|
|
9979
|
-
*
|
|
9980
|
-
* A generic can be added to specify the type of plugins
|
|
9981
|
-
* that are being retrieved.
|
|
9982
|
-
*
|
|
9983
|
-
* ```ts
|
|
9984
|
-
* cms.plugins.all<ColorPlugin>("color").forEach(color => {
|
|
9985
|
-
* console.log(color.name, color.hex)
|
|
9986
|
-
* })
|
|
9987
|
-
* ```
|
|
9988
|
-
*
|
|
9989
|
-
* @typeparam P A subclass of Plugin. Optional.
|
|
9990
|
-
* @param type The name of the plugin
|
|
9991
|
-
* @returns An array of all plugins of the given type.
|
|
9992
|
-
*/
|
|
9993
|
-
all(type2) {
|
|
9994
|
-
return this.findOrCreateMap(type2).all();
|
|
9995
|
-
}
|
|
9996
|
-
}
|
|
9997
|
-
class PluginType {
|
|
9998
|
-
/**
|
|
9999
|
-
*
|
|
10000
|
-
* @param __type The `__type` of plugin being managed.
|
|
10001
|
-
*/
|
|
10002
|
-
constructor(__type, events) {
|
|
10003
|
-
/**
|
|
10004
|
-
* @ignore
|
|
10005
|
-
*/
|
|
10006
|
-
__publicField(this, "__plugins", {});
|
|
10007
|
-
this.__type = __type;
|
|
10008
|
-
this.events = events;
|
|
10009
|
-
}
|
|
10010
|
-
/**
|
|
10011
|
-
* Adds a new plugin to the collection.
|
|
10012
|
-
*
|
|
10013
|
-
* ### Example
|
|
10014
|
-
*
|
|
10015
|
-
* ```ts
|
|
10016
|
-
* interface ColorPlugin extends Plugin {
|
|
10017
|
-
* hex: string
|
|
10018
|
-
* }
|
|
10019
|
-
*
|
|
10020
|
-
* const colorPlugins = new PluginType<ColorPlugin>("color")
|
|
10021
|
-
*
|
|
10022
|
-
* colorPlugins.add({ name: "red", hex: "#f00" })
|
|
10023
|
-
* ```
|
|
10024
|
-
*
|
|
10025
|
-
* @param plugin A new plugin. The `__type` is optional and will be added if it's missing.
|
|
10026
|
-
*/
|
|
10027
|
-
add(plugin) {
|
|
10028
|
-
const p = plugin;
|
|
10029
|
-
if (!p.__type) {
|
|
10030
|
-
p.__type = this.__type;
|
|
10031
|
-
}
|
|
10032
|
-
this.__plugins[p.name] = p;
|
|
10033
|
-
this.events.dispatch({ type: `plugin:add:${this.__type}` });
|
|
10034
|
-
}
|
|
10035
|
-
all() {
|
|
10036
|
-
return Object.keys(this.__plugins).map((name2) => this.__plugins[name2]);
|
|
10037
|
-
}
|
|
10038
|
-
/**
|
|
10039
|
-
*
|
|
10040
|
-
* Looks up a plugin by it's `name`.
|
|
10041
|
-
*
|
|
10042
|
-
* ### Example
|
|
10043
|
-
*
|
|
10044
|
-
* ```ts
|
|
10045
|
-
* const colorPlugins = new PluginType<ColorPlugin>("color")
|
|
10046
|
-
*
|
|
10047
|
-
* colorPlugins.add({ name: "red", hex: "#f00" })
|
|
10048
|
-
*
|
|
10049
|
-
* colorPlugins.find("red") // { __type: "color", name: "red", hex: "#f00" }
|
|
10050
|
-
* colorPlugin.find("large") // undefined
|
|
10051
|
-
* ```
|
|
10052
|
-
*
|
|
10053
|
-
* @param name The `name` of the plugin to be retrieved.
|
|
10054
|
-
*/
|
|
10055
|
-
find(name2) {
|
|
10056
|
-
return this.__plugins[name2];
|
|
10057
|
-
}
|
|
10058
|
-
/**
|
|
10059
|
-
* Pass this function a plugin or the `name` of a plugin to have
|
|
10060
|
-
* it be removed from the CMS.
|
|
10061
|
-
*
|
|
10062
|
-
* @param pluginOrName The `name` of a plugin, or the plugin itself.
|
|
10063
|
-
* @returns The plugin that was removed, or `undefined` if it was not found.
|
|
10064
|
-
*/
|
|
10065
|
-
remove(pluginOrName) {
|
|
10066
|
-
const name2 = typeof pluginOrName === "string" ? pluginOrName : pluginOrName.name;
|
|
10067
|
-
const plugin = this.__plugins[name2];
|
|
10068
|
-
delete this.__plugins[name2];
|
|
10069
|
-
this.events.dispatch({ type: `plugin:remove:${this.__type}` });
|
|
10070
|
-
return plugin;
|
|
10071
|
-
}
|
|
10072
|
-
subscribe(cb) {
|
|
10073
|
-
return this.events.subscribe(`plugin:*:${this.__type}`, cb);
|
|
10074
|
-
}
|
|
10075
|
-
}
|
|
10076
10141
|
class EventBus {
|
|
10077
10142
|
constructor() {
|
|
10078
10143
|
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
@@ -10151,6 +10216,19 @@ class Listener {
|
|
|
10151
10216
|
return !ignoresEvent;
|
|
10152
10217
|
}
|
|
10153
10218
|
}
|
|
10219
|
+
class Flags {
|
|
10220
|
+
constructor(events) {
|
|
10221
|
+
__publicField(this, "_flags", /* @__PURE__ */ new Map());
|
|
10222
|
+
this.events = events;
|
|
10223
|
+
}
|
|
10224
|
+
get(key) {
|
|
10225
|
+
return this._flags.get(key);
|
|
10226
|
+
}
|
|
10227
|
+
set(key, value) {
|
|
10228
|
+
this._flags.set(key, value);
|
|
10229
|
+
this.events.dispatch({ type: "flag:set", key, value });
|
|
10230
|
+
}
|
|
10231
|
+
}
|
|
10154
10232
|
const EDITORIAL_WORKFLOW_STATUS = {
|
|
10155
10233
|
QUEUED: "queued",
|
|
10156
10234
|
PROCESSING: "processing",
|
|
@@ -10238,6 +10316,26 @@ const MEDIA_WORKFLOW_STATUS_TO_STEP = {
|
|
|
10238
10316
|
[EDITORIAL_WORKFLOW_STATUS.COMPLETE]: MEDIA_WORKFLOW_STEP.COMPLETE
|
|
10239
10317
|
};
|
|
10240
10318
|
const s3ErrorRegex = /<Error>.*<Code>(.+)<\/Code>.*<Message>(.+)<\/Message>.*/;
|
|
10319
|
+
const CANONICAL_THUMBNAIL_SIZES = [
|
|
10320
|
+
{ w: 75, h: 75 },
|
|
10321
|
+
{ w: 400, h: 400 },
|
|
10322
|
+
{ w: 1e3, h: 1e3 }
|
|
10323
|
+
];
|
|
10324
|
+
const RENAME_ERROR_CODES = [
|
|
10325
|
+
"NOT_FOUND",
|
|
10326
|
+
"NAME_COLLISION",
|
|
10327
|
+
"INVALID_FILENAME",
|
|
10328
|
+
"INVALID_PATH",
|
|
10329
|
+
"UNAUTHORIZED",
|
|
10330
|
+
"UNSUPPORTED",
|
|
10331
|
+
"BACKEND_FAILURE"
|
|
10332
|
+
];
|
|
10333
|
+
class MediaRenameCancelled extends Error {
|
|
10334
|
+
constructor() {
|
|
10335
|
+
super("Media rename cancelled.");
|
|
10336
|
+
__publicField(this, "ERR_TYPE", "MediaRenameCancelled");
|
|
10337
|
+
}
|
|
10338
|
+
}
|
|
10241
10339
|
class DummyMediaStore {
|
|
10242
10340
|
constructor() {
|
|
10243
10341
|
__publicField(this, "accept", "*");
|
|
@@ -10279,10 +10377,9 @@ class TinaMediaStore {
|
|
|
10279
10377
|
__publicField(this, "workflowBranchOverride");
|
|
10280
10378
|
__publicField(this, "mediaWorkflowInProgress", false);
|
|
10281
10379
|
/**
|
|
10282
|
-
*
|
|
10283
|
-
* instance property rather than a prototype method on purpose: the media
|
|
10380
|
+
* An instance property rather than a prototype method on purpose: the media
|
|
10284
10381
|
* manager decides whether to offer the action by checking whether the store
|
|
10285
|
-
* defines `rename`, so
|
|
10382
|
+
* defines `rename`, so an instance that cannot rename must not carry one — a
|
|
10286
10383
|
* prototype method would advertise support everywhere and surface an action
|
|
10287
10384
|
* that always fails.
|
|
10288
10385
|
*/
|
|
@@ -10300,8 +10397,8 @@ class TinaMediaStore {
|
|
|
10300
10397
|
this.isStatic = true;
|
|
10301
10398
|
this.staticMedia = staticMedia;
|
|
10302
10399
|
}
|
|
10303
|
-
if (!this.isStatic && (
|
|
10304
|
-
this.rename = (from, to2) => this.rename_local(from, to2);
|
|
10400
|
+
if (!this.isStatic && !this.isUnsupportedSelfHostedRepoMedia()) {
|
|
10401
|
+
this.rename = ((_b = (_a = cms == null ? void 0 : cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isLocalMode) ? (from, to2) => this.rename_local(from, to2) : (from, to2) => this.rename_cloud(from, to2);
|
|
10305
10402
|
}
|
|
10306
10403
|
}
|
|
10307
10404
|
/**
|
|
@@ -10347,27 +10444,29 @@ class TinaMediaStore {
|
|
|
10347
10444
|
return await this.api.authProvider.isAuthenticated();
|
|
10348
10445
|
}
|
|
10349
10446
|
/**
|
|
10350
|
-
*
|
|
10351
|
-
*
|
|
10352
|
-
*
|
|
10353
|
-
*
|
|
10354
|
-
*
|
|
10355
|
-
* value is concatenated into a URL.
|
|
10356
|
-
*
|
|
10357
|
-
* `Client.setBranch()` runs the constructor's `options.branch` through
|
|
10358
|
-
* `encodeURIComponent` without a guard, so an unset `options.branch`
|
|
10359
|
-
* lands here as the literal string `"undefined"`. We treat that and the
|
|
10360
|
-
* empty case as no-branch so we don't send `?branch=undefined` to the
|
|
10361
|
-
* assets-api (which would route the call to a non-existent staging path).
|
|
10447
|
+
* The v2 cloud endpoint and the local dev server both filter by `ext` before
|
|
10448
|
+
* paginating. `staticMedia` is a build-time snapshot with no such pass, and
|
|
10449
|
+
* filtering a page client-side would leave a near-empty grid while matches
|
|
10450
|
+
* sit further down — so a static store reports no support and the control
|
|
10451
|
+
* stays hidden, the same way `searchable` is gated.
|
|
10362
10452
|
*/
|
|
10363
|
-
|
|
10364
|
-
|
|
10365
|
-
|
|
10366
|
-
|
|
10453
|
+
get extensionFilterable() {
|
|
10454
|
+
return !this.isStatic;
|
|
10455
|
+
}
|
|
10456
|
+
/**
|
|
10457
|
+
* `Client.setBranch()` encodes an unset branch to the literal `"undefined"`,
|
|
10458
|
+
* which the assets API would read as a real (non-existent) staging path.
|
|
10459
|
+
*/
|
|
10460
|
+
currentBranch() {
|
|
10461
|
+
if (this.workflowBranchOverride) return this.workflowBranchOverride;
|
|
10367
10462
|
if (!this.api.branch) return "";
|
|
10368
10463
|
const decoded = decodeURIComponent(this.api.branch);
|
|
10369
|
-
|
|
10370
|
-
|
|
10464
|
+
return decoded === "undefined" ? "" : decoded;
|
|
10465
|
+
}
|
|
10466
|
+
/** `this.api.branch` arrives encoded, so encode the decoded name once here. */
|
|
10467
|
+
encodedBranchParam() {
|
|
10468
|
+
const branch = this.currentBranch();
|
|
10469
|
+
return branch ? encodeURIComponent(branch) : "";
|
|
10371
10470
|
}
|
|
10372
10471
|
shortStableHash(input) {
|
|
10373
10472
|
let hash = 2166136261;
|
|
@@ -10405,7 +10504,7 @@ class TinaMediaStore {
|
|
|
10405
10504
|
const encodedBranch = this.encodedBranchParam();
|
|
10406
10505
|
return encodedBranch ? `?branch=${encodedBranch}` : "";
|
|
10407
10506
|
}
|
|
10408
|
-
requestMediaBranchChoice(branchName, baseBranch,
|
|
10507
|
+
requestMediaBranchChoice(branchName, baseBranch, request) {
|
|
10409
10508
|
if (!this.cms.events.hasExplicitListenerFor("media:workflow:confirm-branch")) {
|
|
10410
10509
|
throw new Error(
|
|
10411
10510
|
"Cannot start a media editorial workflow: no branch prompt is mounted. Ensure <MediaWorkflowOverlay /> is rendered (TinaCloudProvider mounts it automatically)."
|
|
@@ -10416,12 +10515,13 @@ class TinaMediaStore {
|
|
|
10416
10515
|
type: "media:workflow:confirm-branch",
|
|
10417
10516
|
branchName,
|
|
10418
10517
|
baseBranch,
|
|
10518
|
+
// A rename on a protected branch can only go through the workflow.
|
|
10519
|
+
allowSaveToProtectedBranch: request.opType !== "rename",
|
|
10419
10520
|
onConfirm: async (selectedBranchName) => {
|
|
10420
10521
|
const context = await this.prepareMediaBranch(
|
|
10421
10522
|
selectedBranchName,
|
|
10422
10523
|
baseBranch,
|
|
10423
|
-
|
|
10424
|
-
repoPath
|
|
10524
|
+
request
|
|
10425
10525
|
);
|
|
10426
10526
|
resolve({
|
|
10427
10527
|
kind: "workflow",
|
|
@@ -10433,7 +10533,7 @@ class TinaMediaStore {
|
|
|
10433
10533
|
});
|
|
10434
10534
|
});
|
|
10435
10535
|
}
|
|
10436
|
-
async prepareMediaBranch(branchName, baseBranch,
|
|
10536
|
+
async prepareMediaBranch(branchName, baseBranch, request) {
|
|
10437
10537
|
if (this.mediaWorkflowInProgress) {
|
|
10438
10538
|
throw new Error("A media workflow is already in progress.");
|
|
10439
10539
|
}
|
|
@@ -10448,8 +10548,9 @@ class TinaMediaStore {
|
|
|
10448
10548
|
branchName,
|
|
10449
10549
|
baseBranch,
|
|
10450
10550
|
prTitle: getEditorialWorkflowPrTitle(branchName),
|
|
10451
|
-
operation: opType,
|
|
10452
|
-
repoPath
|
|
10551
|
+
operation: request.opType,
|
|
10552
|
+
repoPath: request.repoPath,
|
|
10553
|
+
targetRepoPath: request.targetRepoPath
|
|
10453
10554
|
});
|
|
10454
10555
|
const branchContext = {
|
|
10455
10556
|
branchName: workflow.branchName || branchName,
|
|
@@ -10525,12 +10626,10 @@ class TinaMediaStore {
|
|
|
10525
10626
|
const branchName = `media-${opType}-${mediaSlug}`;
|
|
10526
10627
|
const repoFilename = opType === "upload" && filename ? sanitizeFilename(filename) : filename;
|
|
10527
10628
|
const repoPath = this.joinMediaPath(directory, repoFilename);
|
|
10528
|
-
return this.requestMediaBranchChoice(
|
|
10529
|
-
branchName,
|
|
10530
|
-
baseBranch,
|
|
10629
|
+
return this.requestMediaBranchChoice(branchName, baseBranch, {
|
|
10531
10630
|
opType,
|
|
10532
10631
|
repoPath
|
|
10533
|
-
);
|
|
10632
|
+
});
|
|
10534
10633
|
}
|
|
10535
10634
|
async waitForRequestStatus(requestId, timeoutMessage) {
|
|
10536
10635
|
const startTime = Date.now();
|
|
@@ -10794,6 +10893,160 @@ class TinaMediaStore {
|
|
|
10794
10893
|
lastSlash === -1 ? to2 : to2.slice(lastSlash + 1)
|
|
10795
10894
|
);
|
|
10796
10895
|
}
|
|
10896
|
+
/**
|
|
10897
|
+
* `from`/`to` are media-root-relative `directory/filename` paths. `to` is
|
|
10898
|
+
* already sanitised by `previewRename` and is passed through untouched.
|
|
10899
|
+
*/
|
|
10900
|
+
async rename_cloud(from, to2) {
|
|
10901
|
+
this.setup();
|
|
10902
|
+
if (!await this.isAuthenticated()) {
|
|
10903
|
+
throw new MediaRenameError({
|
|
10904
|
+
code: "UNAUTHORIZED",
|
|
10905
|
+
message: "You don't have permission to rename this file."
|
|
10906
|
+
});
|
|
10907
|
+
}
|
|
10908
|
+
const decision = await this.prepareRenameBranch(from, to2);
|
|
10909
|
+
if (decision.kind === "cancelled") {
|
|
10910
|
+
throw new MediaRenameCancelled();
|
|
10911
|
+
}
|
|
10912
|
+
if (decision.kind === "workflow") {
|
|
10913
|
+
return this.renameCloudViaWorkflow(from, to2, decision.context);
|
|
10914
|
+
}
|
|
10915
|
+
return this.renameCloudDirect(from, to2);
|
|
10916
|
+
}
|
|
10917
|
+
/** `currentBranch()` is the workflow branch while one is active. */
|
|
10918
|
+
async postCloudRename(from, to2) {
|
|
10919
|
+
const branch = this.currentBranch() || void 0;
|
|
10920
|
+
const res = await this.api.authProvider.fetchWithToken(
|
|
10921
|
+
`${this.url}/rename`,
|
|
10922
|
+
{
|
|
10923
|
+
method: "POST",
|
|
10924
|
+
headers: { "Content-Type": "application/json" },
|
|
10925
|
+
body: JSON.stringify({ from, to: to2, branch })
|
|
10926
|
+
}
|
|
10927
|
+
);
|
|
10928
|
+
const body = await res.json().catch(() => null);
|
|
10929
|
+
if (res.status !== 200 || (body == null ? void 0 : body.success) !== true) {
|
|
10930
|
+
throw this.toCloudRenameError(res.status, body);
|
|
10931
|
+
}
|
|
10932
|
+
return body;
|
|
10933
|
+
}
|
|
10934
|
+
async renameCloudDirect(from, to2) {
|
|
10935
|
+
const result = await this.postCloudRename(from, to2);
|
|
10936
|
+
if (result.requestId) {
|
|
10937
|
+
try {
|
|
10938
|
+
await this.waitForRequestStatus(
|
|
10939
|
+
result.requestId,
|
|
10940
|
+
"Time out waiting for rename to complete"
|
|
10941
|
+
);
|
|
10942
|
+
} catch (error) {
|
|
10943
|
+
const detail = error instanceof Error && error.message ? `${error.message}. ` : "Failed to confirm the rename. ";
|
|
10944
|
+
throw new MediaRenameError({
|
|
10945
|
+
code: "BACKEND_FAILURE",
|
|
10946
|
+
message: `${detail}The file may still have been renamed — refresh the media library to check.`
|
|
10947
|
+
});
|
|
10948
|
+
}
|
|
10949
|
+
}
|
|
10950
|
+
return this.resolveRenamedMedia(result.path || to2, result.src);
|
|
10951
|
+
}
|
|
10952
|
+
/**
|
|
10953
|
+
* Completion is the workflow status, not the rename request status: only the
|
|
10954
|
+
* former waits for the branch, the media index and the pull request.
|
|
10955
|
+
*/
|
|
10956
|
+
async renameCloudViaWorkflow(from, to2, branchContext) {
|
|
10957
|
+
let renamed;
|
|
10958
|
+
try {
|
|
10959
|
+
const result = await this.postCloudRename(from, to2);
|
|
10960
|
+
await this.finalizeMediaWorkflow(branchContext, async () => {
|
|
10961
|
+
renamed = await this.resolveRenamedMedia(result.path || to2, result.src);
|
|
10962
|
+
});
|
|
10963
|
+
} catch (err) {
|
|
10964
|
+
this.resetWorkflowState();
|
|
10965
|
+
this.cms.events.dispatch({ type: "media:workflow:finish" });
|
|
10966
|
+
throw err;
|
|
10967
|
+
}
|
|
10968
|
+
if (!renamed) {
|
|
10969
|
+
throw new MediaRenameError({
|
|
10970
|
+
code: "BACKEND_FAILURE",
|
|
10971
|
+
message: "The rename was staged but the branch workflow did not complete. Check the branch in TinaCloud before trying again."
|
|
10972
|
+
});
|
|
10973
|
+
}
|
|
10974
|
+
return renamed;
|
|
10975
|
+
}
|
|
10976
|
+
async prepareRenameBranch(from, to2) {
|
|
10977
|
+
if (!this.api.usingProtectedBranch()) return { kind: "direct" };
|
|
10978
|
+
const baseBranch = decodeURIComponent(this.api.branch || "");
|
|
10979
|
+
const { directory, filename } = this.splitMediaPath(from);
|
|
10980
|
+
const branchName = `media-rename-${this.branchSlugForMediaPath(
|
|
10981
|
+
directory,
|
|
10982
|
+
filename
|
|
10983
|
+
)}`;
|
|
10984
|
+
return this.requestMediaBranchChoice(branchName, baseBranch, {
|
|
10985
|
+
opType: "rename",
|
|
10986
|
+
repoPath: from,
|
|
10987
|
+
targetRepoPath: to2
|
|
10988
|
+
});
|
|
10989
|
+
}
|
|
10990
|
+
splitMediaPath(path) {
|
|
10991
|
+
const lastSlash = path.lastIndexOf("/");
|
|
10992
|
+
return lastSlash === -1 ? { directory: "", filename: path } : {
|
|
10993
|
+
directory: path.slice(0, lastSlash),
|
|
10994
|
+
filename: path.slice(lastSlash + 1)
|
|
10995
|
+
};
|
|
10996
|
+
}
|
|
10997
|
+
/**
|
|
10998
|
+
* The listing is the source of truth for `src` (staging path, per-stage CDN
|
|
10999
|
+
* host) and thumbnails; the rename response is the fallback when the entry
|
|
11000
|
+
* isn't on the first page.
|
|
11001
|
+
*/
|
|
11002
|
+
async resolveRenamedMedia(targetPath, srcFromResponse) {
|
|
11003
|
+
const { directory, filename } = this.splitMediaPath(targetPath);
|
|
11004
|
+
try {
|
|
11005
|
+
const listed = await this.list({
|
|
11006
|
+
directory,
|
|
11007
|
+
limit: 100,
|
|
11008
|
+
thumbnailSizes: CANONICAL_THUMBNAIL_SIZES
|
|
11009
|
+
});
|
|
11010
|
+
const entry = listed.items.find(
|
|
11011
|
+
(item) => item.type === "file" && item.filename === filename
|
|
11012
|
+
);
|
|
11013
|
+
if (entry) return entry;
|
|
11014
|
+
} catch (error) {
|
|
11015
|
+
console.error("Failed to fetch the canonical media entry:", error);
|
|
11016
|
+
}
|
|
11017
|
+
const src = srcFromResponse || "";
|
|
11018
|
+
return {
|
|
11019
|
+
type: "file",
|
|
11020
|
+
id: filename,
|
|
11021
|
+
filename,
|
|
11022
|
+
directory,
|
|
11023
|
+
src,
|
|
11024
|
+
thumbnails: CANONICAL_THUMBNAIL_SIZES.reduce(
|
|
11025
|
+
(acc, size) => {
|
|
11026
|
+
acc[`${size.w}x${size.h}`] = this.genThumbnail(src, size);
|
|
11027
|
+
return acc;
|
|
11028
|
+
},
|
|
11029
|
+
{}
|
|
11030
|
+
)
|
|
11031
|
+
};
|
|
11032
|
+
}
|
|
11033
|
+
toCloudRenameError(status, body) {
|
|
11034
|
+
const message = typeof (body == null ? void 0 : body.message) === "string" && body.message ? body.message : "Failed to rename the file.";
|
|
11035
|
+
if (RENAME_ERROR_CODES.includes(body == null ? void 0 : body.code)) {
|
|
11036
|
+
return new MediaRenameError({ code: body.code, message });
|
|
11037
|
+
}
|
|
11038
|
+
let code;
|
|
11039
|
+
if (status === 401 || status === 403) {
|
|
11040
|
+
code = "UNAUTHORIZED";
|
|
11041
|
+
} else if (status === 404) {
|
|
11042
|
+
code = "NOT_FOUND";
|
|
11043
|
+
} else if (status === 409) {
|
|
11044
|
+
code = "NAME_COLLISION";
|
|
11045
|
+
} else {
|
|
11046
|
+
code = "BACKEND_FAILURE";
|
|
11047
|
+
}
|
|
11048
|
+
return new MediaRenameError({ code, message });
|
|
11049
|
+
}
|
|
10797
11050
|
toRenameError(status, body) {
|
|
10798
11051
|
if (body == null ? void 0 : body.code) {
|
|
10799
11052
|
return new MediaRenameError({
|
|
@@ -10821,6 +11074,7 @@ class TinaMediaStore {
|
|
|
10821
11074
|
return !this.isLocal ? `${src}?fit=crop&max-w=${dimensions.w}&max-h=${dimensions.h}` : src;
|
|
10822
11075
|
}
|
|
10823
11076
|
async list(options) {
|
|
11077
|
+
var _a, _b;
|
|
10824
11078
|
this.setup();
|
|
10825
11079
|
if (this.staticMedia) {
|
|
10826
11080
|
const offset2 = options.offset || 0;
|
|
@@ -10852,13 +11106,16 @@ class TinaMediaStore {
|
|
|
10852
11106
|
nextOffset: hasMore2 ? Number(offset2) + 20 : null
|
|
10853
11107
|
};
|
|
10854
11108
|
}
|
|
10855
|
-
return {
|
|
11109
|
+
return {
|
|
11110
|
+
items: media,
|
|
11111
|
+
nextOffset: hasMore ? Number(offset2) + 20 : null
|
|
11112
|
+
};
|
|
10856
11113
|
}
|
|
10857
11114
|
let res;
|
|
10858
11115
|
if (!this.isLocal) {
|
|
10859
11116
|
const encodedBranch = this.encodedBranchParam();
|
|
10860
11117
|
res = await this.api.authProvider.fetchWithToken(
|
|
10861
|
-
`${this.listUrl}/list/${options.directory || ""}?limit=${options.limit || 20}${options.offset ? `&cursor=${options.offset}` : ""}${encodedBranch ? `&branch=${encodedBranch}` : ""}${options.search ? `&search=${encodeURIComponent(options.search)}` : ""}`
|
|
11118
|
+
`${this.listUrl}/list/${options.directory || ""}?limit=${options.limit || 20}${options.offset ? `&cursor=${options.offset}` : ""}${encodedBranch ? `&branch=${encodedBranch}` : ""}${options.search ? `&search=${encodeURIComponent(options.search)}` : ""}${((_a = options.ext) == null ? void 0 : _a.length) ? `&ext=${encodeURIComponent(options.ext.join(","))}` : ""}`
|
|
10862
11119
|
);
|
|
10863
11120
|
if (res.status == 401) {
|
|
10864
11121
|
throw E_UNAUTHORIZED;
|
|
@@ -10868,7 +11125,7 @@ class TinaMediaStore {
|
|
|
10868
11125
|
}
|
|
10869
11126
|
} else {
|
|
10870
11127
|
res = await this.fetchFunction(
|
|
10871
|
-
`${this.url}/list/${options.directory || ""}?limit=${options.limit || 20}${options.offset ? `&cursor=${options.offset}` : ""}${options.search ? `&search=${encodeURIComponent(options.search)}` : ""}`
|
|
11128
|
+
`${this.url}/list/${options.directory || ""}?limit=${options.limit || 20}${options.offset ? `&cursor=${options.offset}` : ""}${options.search ? `&search=${encodeURIComponent(options.search)}` : ""}${((_b = options.ext) == null ? void 0 : _b.length) ? `&ext=${encodeURIComponent(options.ext.join(","))}` : ""}`
|
|
10872
11129
|
);
|
|
10873
11130
|
if (res.status == 404) {
|
|
10874
11131
|
throw E_BAD_ROUTE;
|
|
@@ -11113,17 +11370,217 @@ const E_SELF_HOSTED_MEDIA = new MediaListError({
|
|
|
11113
11370
|
message: "Self-hosted TinaCMS can't serve media from your repo through TinaCloud. Configure an external media store (e.g. S3, Cloudinary, DigitalOcean Spaces, or Azure) with media.loadCustomStore, or add media to your repo manually.",
|
|
11114
11371
|
docsLink: "https://tina.io/docs/r/backend-media-handler/"
|
|
11115
11372
|
});
|
|
11116
|
-
class
|
|
11373
|
+
class PluginTypeManager {
|
|
11117
11374
|
constructor(events) {
|
|
11118
|
-
|
|
11375
|
+
/**
|
|
11376
|
+
* @ignore
|
|
11377
|
+
*/
|
|
11378
|
+
__publicField(this, "plugins", {});
|
|
11119
11379
|
this.events = events;
|
|
11120
11380
|
}
|
|
11121
|
-
|
|
11122
|
-
|
|
11381
|
+
/**
|
|
11382
|
+
* Gets the [[PluginType|collection of plugins]] for the given type.
|
|
11383
|
+
*
|
|
11384
|
+
* #### Example: Basic Usage
|
|
11385
|
+
*
|
|
11386
|
+
* ```ts
|
|
11387
|
+
* const colorPlugins = cms.plugins.get("color")
|
|
11388
|
+
* ```
|
|
11389
|
+
*
|
|
11390
|
+
* #### Example: Advanced Types
|
|
11391
|
+
*
|
|
11392
|
+
* A type param can be added to specify the kind of Plugin
|
|
11393
|
+
* that is being listed.
|
|
11394
|
+
*
|
|
11395
|
+
* ```ts
|
|
11396
|
+
* const colorPlugins = cms.plugins.get<ColorPlugin>("color")
|
|
11397
|
+
* ```
|
|
11398
|
+
*
|
|
11399
|
+
* @param type The type of plugins to be retrieved
|
|
11400
|
+
* @typeparam P A subclass of Plugin. Optional.
|
|
11401
|
+
*/
|
|
11402
|
+
getType(type2) {
|
|
11403
|
+
return this.plugins[type2] = this.plugins[type2] || new PluginType(type2, this.events);
|
|
11123
11404
|
}
|
|
11124
|
-
|
|
11125
|
-
|
|
11126
|
-
|
|
11405
|
+
/**
|
|
11406
|
+
* An alias to [[get]]
|
|
11407
|
+
*
|
|
11408
|
+
* ### !DEPRECATED!
|
|
11409
|
+
*
|
|
11410
|
+
* This name is unnecessarily verbose and weird.
|
|
11411
|
+
*/
|
|
11412
|
+
findOrCreateMap(type2) {
|
|
11413
|
+
return this.getType(type2);
|
|
11414
|
+
}
|
|
11415
|
+
/**
|
|
11416
|
+
* Adds a Plugin to the CMS.
|
|
11417
|
+
*
|
|
11418
|
+
* #### Example: Basic Usage
|
|
11419
|
+
*
|
|
11420
|
+
* ```js
|
|
11421
|
+
* cms.plugins.add({ __type: "color", name: "red" })
|
|
11422
|
+
* ```
|
|
11423
|
+
*
|
|
11424
|
+
* #### Example: Advanced Types
|
|
11425
|
+
*
|
|
11426
|
+
* ```ts
|
|
11427
|
+
* interface ColorPlugin extends Plugin {
|
|
11428
|
+
* __type: "color"
|
|
11429
|
+
* hex: string
|
|
11430
|
+
* rgb: string
|
|
11431
|
+
* }
|
|
11432
|
+
*
|
|
11433
|
+
* cms.plugins.add<ColorPlugin>({
|
|
11434
|
+
* __type: "color",
|
|
11435
|
+
* name: "red",
|
|
11436
|
+
* hex: "#FF0000",
|
|
11437
|
+
* rgb: "RGBA(255, 0, 0, 1)"
|
|
11438
|
+
* })
|
|
11439
|
+
* ```
|
|
11440
|
+
*
|
|
11441
|
+
* @typeparam P A subclass of Plugin. Optional.
|
|
11442
|
+
* @param plugin
|
|
11443
|
+
* @todo Consider returning the plugin which was just added.
|
|
11444
|
+
*/
|
|
11445
|
+
add(plugin) {
|
|
11446
|
+
this.findOrCreateMap(plugin.__type).add(plugin);
|
|
11447
|
+
}
|
|
11448
|
+
/**
|
|
11449
|
+
* Removes the given plugin from the CMS.
|
|
11450
|
+
*
|
|
11451
|
+
* #### Example
|
|
11452
|
+
*
|
|
11453
|
+
* In this example a plugin is added to the CMS and removed
|
|
11454
|
+
* 5 seconds later.
|
|
11455
|
+
*
|
|
11456
|
+
* ```ts
|
|
11457
|
+
* const redPlugin = {
|
|
11458
|
+
* __type: "color",
|
|
11459
|
+
* name: "red",
|
|
11460
|
+
* hex: "#FF0000",
|
|
11461
|
+
* rgb: "RGBA(255, 0, 0, 1)"
|
|
11462
|
+
* }
|
|
11463
|
+
*
|
|
11464
|
+
* cms.plugins.add(redPlugin)
|
|
11465
|
+
*
|
|
11466
|
+
* setTimeout(() => {
|
|
11467
|
+
* cms.plugins.remove(redPlugin)
|
|
11468
|
+
* }, 5000)
|
|
11469
|
+
* ```
|
|
11470
|
+
*
|
|
11471
|
+
* @typeparam P A subclass of Plugin. Optional.
|
|
11472
|
+
* @param plugin The plugin to be removed from the CMS.
|
|
11473
|
+
*/
|
|
11474
|
+
remove(plugin) {
|
|
11475
|
+
this.findOrCreateMap(plugin.__type).remove(plugin);
|
|
11476
|
+
}
|
|
11477
|
+
/**
|
|
11478
|
+
* Returns a list of all the plugins of the given type.
|
|
11479
|
+
*
|
|
11480
|
+
* #### Example: Basic Usage
|
|
11481
|
+
*
|
|
11482
|
+
* ```ts
|
|
11483
|
+
* cms.plugins.all("color").forEach(color => {
|
|
11484
|
+
* console.log(color.name)
|
|
11485
|
+
* })
|
|
11486
|
+
* ```
|
|
11487
|
+
*
|
|
11488
|
+
* #### Example: Advanced Types
|
|
11489
|
+
*
|
|
11490
|
+
* A generic can be added to specify the type of plugins
|
|
11491
|
+
* that are being retrieved.
|
|
11492
|
+
*
|
|
11493
|
+
* ```ts
|
|
11494
|
+
* cms.plugins.all<ColorPlugin>("color").forEach(color => {
|
|
11495
|
+
* console.log(color.name, color.hex)
|
|
11496
|
+
* })
|
|
11497
|
+
* ```
|
|
11498
|
+
*
|
|
11499
|
+
* @typeparam P A subclass of Plugin. Optional.
|
|
11500
|
+
* @param type The name of the plugin
|
|
11501
|
+
* @returns An array of all plugins of the given type.
|
|
11502
|
+
*/
|
|
11503
|
+
all(type2) {
|
|
11504
|
+
return this.findOrCreateMap(type2).all();
|
|
11505
|
+
}
|
|
11506
|
+
}
|
|
11507
|
+
class PluginType {
|
|
11508
|
+
/**
|
|
11509
|
+
*
|
|
11510
|
+
* @param __type The `__type` of plugin being managed.
|
|
11511
|
+
*/
|
|
11512
|
+
constructor(__type, events) {
|
|
11513
|
+
/**
|
|
11514
|
+
* @ignore
|
|
11515
|
+
*/
|
|
11516
|
+
__publicField(this, "__plugins", {});
|
|
11517
|
+
this.__type = __type;
|
|
11518
|
+
this.events = events;
|
|
11519
|
+
}
|
|
11520
|
+
/**
|
|
11521
|
+
* Adds a new plugin to the collection.
|
|
11522
|
+
*
|
|
11523
|
+
* ### Example
|
|
11524
|
+
*
|
|
11525
|
+
* ```ts
|
|
11526
|
+
* interface ColorPlugin extends Plugin {
|
|
11527
|
+
* hex: string
|
|
11528
|
+
* }
|
|
11529
|
+
*
|
|
11530
|
+
* const colorPlugins = new PluginType<ColorPlugin>("color")
|
|
11531
|
+
*
|
|
11532
|
+
* colorPlugins.add({ name: "red", hex: "#f00" })
|
|
11533
|
+
* ```
|
|
11534
|
+
*
|
|
11535
|
+
* @param plugin A new plugin. The `__type` is optional and will be added if it's missing.
|
|
11536
|
+
*/
|
|
11537
|
+
add(plugin) {
|
|
11538
|
+
const p = plugin;
|
|
11539
|
+
if (!p.__type) {
|
|
11540
|
+
p.__type = this.__type;
|
|
11541
|
+
}
|
|
11542
|
+
this.__plugins[p.name] = p;
|
|
11543
|
+
this.events.dispatch({ type: `plugin:add:${this.__type}` });
|
|
11544
|
+
}
|
|
11545
|
+
all() {
|
|
11546
|
+
return Object.keys(this.__plugins).map((name2) => this.__plugins[name2]);
|
|
11547
|
+
}
|
|
11548
|
+
/**
|
|
11549
|
+
*
|
|
11550
|
+
* Looks up a plugin by it's `name`.
|
|
11551
|
+
*
|
|
11552
|
+
* ### Example
|
|
11553
|
+
*
|
|
11554
|
+
* ```ts
|
|
11555
|
+
* const colorPlugins = new PluginType<ColorPlugin>("color")
|
|
11556
|
+
*
|
|
11557
|
+
* colorPlugins.add({ name: "red", hex: "#f00" })
|
|
11558
|
+
*
|
|
11559
|
+
* colorPlugins.find("red") // { __type: "color", name: "red", hex: "#f00" }
|
|
11560
|
+
* colorPlugin.find("large") // undefined
|
|
11561
|
+
* ```
|
|
11562
|
+
*
|
|
11563
|
+
* @param name The `name` of the plugin to be retrieved.
|
|
11564
|
+
*/
|
|
11565
|
+
find(name2) {
|
|
11566
|
+
return this.__plugins[name2];
|
|
11567
|
+
}
|
|
11568
|
+
/**
|
|
11569
|
+
* Pass this function a plugin or the `name` of a plugin to have
|
|
11570
|
+
* it be removed from the CMS.
|
|
11571
|
+
*
|
|
11572
|
+
* @param pluginOrName The `name` of a plugin, or the plugin itself.
|
|
11573
|
+
* @returns The plugin that was removed, or `undefined` if it was not found.
|
|
11574
|
+
*/
|
|
11575
|
+
remove(pluginOrName) {
|
|
11576
|
+
const name2 = typeof pluginOrName === "string" ? pluginOrName : pluginOrName.name;
|
|
11577
|
+
const plugin = this.__plugins[name2];
|
|
11578
|
+
delete this.__plugins[name2];
|
|
11579
|
+
this.events.dispatch({ type: `plugin:remove:${this.__type}` });
|
|
11580
|
+
return plugin;
|
|
11581
|
+
}
|
|
11582
|
+
subscribe(cb) {
|
|
11583
|
+
return this.events.subscribe(`plugin:*:${this.__type}`, cb);
|
|
11127
11584
|
}
|
|
11128
11585
|
}
|
|
11129
11586
|
const _CMS = class _CMS {
|
|
@@ -11236,14 +11693,28 @@ const _CMS = class _CMS {
|
|
|
11236
11693
|
this.unsubscribeHooks[name2]();
|
|
11237
11694
|
}
|
|
11238
11695
|
if (api.events instanceof EventBus) {
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11696
|
+
let forwardingToCms = null;
|
|
11697
|
+
let forwardingToApi = null;
|
|
11698
|
+
const unsubscribeHost = api.events.subscribe("*", (e) => {
|
|
11699
|
+
if (e === forwardingToApi) return;
|
|
11700
|
+
const previous = forwardingToCms;
|
|
11701
|
+
forwardingToCms = e;
|
|
11702
|
+
try {
|
|
11703
|
+
this.events.dispatch(e);
|
|
11704
|
+
} finally {
|
|
11705
|
+
forwardingToCms = previous;
|
|
11706
|
+
}
|
|
11707
|
+
});
|
|
11708
|
+
const unsubscribeGuest = this.events.subscribe("*", (e) => {
|
|
11709
|
+
if (e === forwardingToCms) return;
|
|
11710
|
+
const previous = forwardingToApi;
|
|
11711
|
+
forwardingToApi = e;
|
|
11712
|
+
try {
|
|
11713
|
+
api.events.dispatch(e);
|
|
11714
|
+
} finally {
|
|
11715
|
+
forwardingToApi = previous;
|
|
11716
|
+
}
|
|
11717
|
+
});
|
|
11247
11718
|
this.unsubscribeHooks[name2] = () => {
|
|
11248
11719
|
unsubscribeHost();
|
|
11249
11720
|
unsubscribeGuest();
|
|
@@ -11580,13 +12051,16 @@ const RenameModal$1 = ({
|
|
|
11580
12051
|
variant: "primary",
|
|
11581
12052
|
disabled: !canSubmit,
|
|
11582
12053
|
onClick: async () => {
|
|
11583
|
-
if (!canSubmit) return;
|
|
11584
12054
|
setProcessing(true);
|
|
11585
12055
|
setError(null);
|
|
11586
12056
|
try {
|
|
11587
12057
|
await renameFunc(sanitized);
|
|
11588
12058
|
close2();
|
|
11589
12059
|
} catch (e) {
|
|
12060
|
+
if ((e == null ? void 0 : e.ERR_TYPE) === "MediaRenameCancelled") {
|
|
12061
|
+
close2();
|
|
12062
|
+
return;
|
|
12063
|
+
}
|
|
11590
12064
|
setError(renameErrorMessage(e, sanitized));
|
|
11591
12065
|
setProcessing(false);
|
|
11592
12066
|
}
|
|
@@ -11696,6 +12170,7 @@ function MediaPicker({
|
|
|
11696
12170
|
allowDelete,
|
|
11697
12171
|
onSelect,
|
|
11698
12172
|
close: close2,
|
|
12173
|
+
accept: fieldAccept,
|
|
11699
12174
|
...props
|
|
11700
12175
|
}) {
|
|
11701
12176
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
@@ -11732,6 +12207,7 @@ function MediaPicker({
|
|
|
11732
12207
|
const [mediaFilter, setMediaFilter] = useState(
|
|
11733
12208
|
"all"
|
|
11734
12209
|
);
|
|
12210
|
+
const [typeFilter, setTypeFilter] = useState("all");
|
|
11735
12211
|
const [offsetHistory, setOffsetHistory] = useState([]);
|
|
11736
12212
|
const offset2 = offsetHistory[offsetHistory.length - 1];
|
|
11737
12213
|
const resetOffset = () => setOffsetHistory([]);
|
|
@@ -11744,8 +12220,25 @@ function MediaPicker({
|
|
|
11744
12220
|
resetList();
|
|
11745
12221
|
setActiveItem(false);
|
|
11746
12222
|
};
|
|
12223
|
+
const changeTypeFilter = (next) => {
|
|
12224
|
+
if (next === typeFilter) return;
|
|
12225
|
+
setTypeFilter(next);
|
|
12226
|
+
setLoadFolders(true);
|
|
12227
|
+
resetOffset();
|
|
12228
|
+
resetList();
|
|
12229
|
+
setActiveItem(false);
|
|
12230
|
+
};
|
|
11747
12231
|
const listRequestRef = useRef(0);
|
|
11748
12232
|
const newMediaSrcsRef = useRef(/* @__PURE__ */ new Set());
|
|
12233
|
+
const fieldExtensions = React__default.useMemo(
|
|
12234
|
+
() => resolveMediaAccept(fieldAccept),
|
|
12235
|
+
[fieldAccept]
|
|
12236
|
+
);
|
|
12237
|
+
const acceptedExtensions = React__default.useMemo(() => {
|
|
12238
|
+
if (!cms.media.store.extensionFilterable) return [];
|
|
12239
|
+
if (fieldExtensions.length) return fieldExtensions;
|
|
12240
|
+
return typeFilter === "all" ? [] : resolveMediaAccept(typeFilter);
|
|
12241
|
+
}, [fieldExtensions, typeFilter, cms.media.store.extensionFilterable]);
|
|
11749
12242
|
async function loadMedia(loadFolders2 = true) {
|
|
11750
12243
|
const requestId = ++listRequestRef.current;
|
|
11751
12244
|
setListState("loading");
|
|
@@ -11760,7 +12253,8 @@ function MediaPicker({
|
|
|
11760
12253
|
{ w: 1e3, h: 1e3 }
|
|
11761
12254
|
],
|
|
11762
12255
|
filesOnly: !loadFolders2,
|
|
11763
|
-
search: debouncedSearch || void 0
|
|
12256
|
+
search: debouncedSearch || void 0,
|
|
12257
|
+
ext: acceptedExtensions.length ? acceptedExtensions : void 0
|
|
11764
12258
|
});
|
|
11765
12259
|
if (requestId !== listRequestRef.current) return;
|
|
11766
12260
|
setList((prev) => {
|
|
@@ -11803,9 +12297,6 @@ function MediaPicker({
|
|
|
11803
12297
|
}, [refreshing]);
|
|
11804
12298
|
useEffect(() => {
|
|
11805
12299
|
if (!cms.media.isConfigured) return;
|
|
11806
|
-
if (refreshing) return;
|
|
11807
|
-
loadMedia(loadFolders);
|
|
11808
|
-
if (loadFolders) setLoadFolders(false);
|
|
11809
12300
|
return cms.events.subscribe(
|
|
11810
12301
|
["media:delete:success", "media:rename:success", "media:pageSize"],
|
|
11811
12302
|
(event) => {
|
|
@@ -11819,7 +12310,19 @@ function MediaPicker({
|
|
|
11819
12310
|
resetList();
|
|
11820
12311
|
}
|
|
11821
12312
|
);
|
|
11822
|
-
}, [
|
|
12313
|
+
}, [cms.media.isConfigured]);
|
|
12314
|
+
useEffect(() => {
|
|
12315
|
+
if (!cms.media.isConfigured) return;
|
|
12316
|
+
if (refreshing) return;
|
|
12317
|
+
loadMedia(loadFolders);
|
|
12318
|
+
if (loadFolders) setLoadFolders(false);
|
|
12319
|
+
}, [
|
|
12320
|
+
offset2,
|
|
12321
|
+
directory,
|
|
12322
|
+
debouncedSearch,
|
|
12323
|
+
acceptedExtensions,
|
|
12324
|
+
cms.media.isConfigured
|
|
12325
|
+
]);
|
|
11823
12326
|
const onClickMediaItem = (item) => {
|
|
11824
12327
|
if (!item) {
|
|
11825
12328
|
setActiveItem(false);
|
|
@@ -11853,12 +12356,12 @@ function MediaPicker({
|
|
|
11853
12356
|
};
|
|
11854
12357
|
}
|
|
11855
12358
|
const [uploading, setUploading] = useState(false);
|
|
11856
|
-
const
|
|
12359
|
+
const globalAccept = Array.isArray(
|
|
11857
12360
|
(_c = (_b = (_a = cms.api.tina.schema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.media) == null ? void 0 : _c.accept
|
|
11858
12361
|
) ? (_f = (_e = (_d = cms.api.tina.schema.schema) == null ? void 0 : _d.config) == null ? void 0 : _e.media) == null ? void 0 : _f.accept.join(",") : (_i = (_h = (_g = cms.api.tina.schema.schema) == null ? void 0 : _g.config) == null ? void 0 : _h.media) == null ? void 0 : _i.accept;
|
|
11859
12362
|
const { getRootProps, getInputProps, isDragActive } = useDropzone({
|
|
11860
|
-
accept: dropzoneAcceptFromString(
|
|
11861
|
-
|
|
12363
|
+
accept: dropzoneAcceptFromExtensions(fieldExtensions) ?? dropzoneAcceptFromString(
|
|
12364
|
+
globalAccept || cms.media.accept || DEFAULT_MEDIA_UPLOAD_TYPES
|
|
11862
12365
|
),
|
|
11863
12366
|
maxSize: cms.media.maxSize,
|
|
11864
12367
|
multiple: true,
|
|
@@ -12075,7 +12578,15 @@ function MediaPicker({
|
|
|
12075
12578
|
setValue: setSearch,
|
|
12076
12579
|
clear: () => setSearch("")
|
|
12077
12580
|
}
|
|
12078
|
-
), /* @__PURE__ */ React__default.createElement("div", { className: "ml-auto" }, /* @__PURE__ */ React__default.createElement(
|
|
12581
|
+
), /* @__PURE__ */ React__default.createElement("div", { className: "ml-auto flex items-center gap-3" }, cms.media.store.extensionFilterable && /* @__PURE__ */ React__default.createElement(
|
|
12582
|
+
MediaTypeFilter,
|
|
12583
|
+
{
|
|
12584
|
+
value: typeFilter,
|
|
12585
|
+
setValue: changeTypeFilter,
|
|
12586
|
+
lockedTo: fieldAccept,
|
|
12587
|
+
lockedExtensions: fieldExtensions
|
|
12588
|
+
}
|
|
12589
|
+
), /* @__PURE__ */ React__default.createElement(
|
|
12079
12590
|
MediaFilterToggle,
|
|
12080
12591
|
{
|
|
12081
12592
|
value: mediaFilter,
|
|
@@ -12340,6 +12851,62 @@ const MediaFilterToggle = ({
|
|
|
12340
12851
|
option.label
|
|
12341
12852
|
)));
|
|
12342
12853
|
};
|
|
12854
|
+
const TYPE_FILTER_LABELS = {
|
|
12855
|
+
image: "Images",
|
|
12856
|
+
video: "Video",
|
|
12857
|
+
audio: "Audio",
|
|
12858
|
+
document: "Documents"
|
|
12859
|
+
};
|
|
12860
|
+
const acceptEntryLabel = (entry) => entry in MEDIA_CATEGORIES ? TYPE_FILTER_LABELS[entry] : entry.toUpperCase();
|
|
12861
|
+
const MediaTypeFilter = ({
|
|
12862
|
+
value,
|
|
12863
|
+
setValue,
|
|
12864
|
+
lockedTo,
|
|
12865
|
+
lockedExtensions
|
|
12866
|
+
}) => {
|
|
12867
|
+
if (lockedExtensions.length) {
|
|
12868
|
+
const entries = Array.isArray(lockedTo) ? lockedTo : [lockedTo];
|
|
12869
|
+
const label = entries.length > 3 ? `${entries.length} types only` : `${entries.map(acceptEntryLabel).join(", ")} only`;
|
|
12870
|
+
const description = `This field accepts ${lockedExtensions.join(", ")}`;
|
|
12871
|
+
return /* @__PURE__ */ React__default.createElement(
|
|
12872
|
+
"span",
|
|
12873
|
+
{
|
|
12874
|
+
className: "grow-0 flex items-center gap-1.5 whitespace-nowrap rounded-lg border border-dashed border-gray-200 bg-gray-100 px-3 py-1.5 text-sm text-gray-500",
|
|
12875
|
+
title: description
|
|
12876
|
+
},
|
|
12877
|
+
/* @__PURE__ */ React__default.createElement(Lock, { className: "w-3.5 h-3.5 opacity-80", "aria-hidden": "true" }),
|
|
12878
|
+
label,
|
|
12879
|
+
/* @__PURE__ */ React__default.createElement("span", { className: "sr-only" }, description)
|
|
12880
|
+
);
|
|
12881
|
+
}
|
|
12882
|
+
const active = value !== "all";
|
|
12883
|
+
return /* @__PURE__ */ React__default.createElement(DropdownMenu, null, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger, { asChild: true }, /* @__PURE__ */ React__default.createElement(
|
|
12884
|
+
"button",
|
|
12885
|
+
{
|
|
12886
|
+
type: "button",
|
|
12887
|
+
className: `grow-0 flex items-center gap-2 whitespace-nowrap rounded-lg border bg-white px-3 py-1.5 text-sm transition-colors ease-out duration-150 ${active ? "border-tina-orange text-tina-orange font-medium" : "border-gray-200 text-gray-700 hover:border-gray-300"}`
|
|
12888
|
+
},
|
|
12889
|
+
active ? TYPE_FILTER_LABELS[value] : "Any type",
|
|
12890
|
+
/* @__PURE__ */ React__default.createElement(
|
|
12891
|
+
ChevronDown,
|
|
12892
|
+
{
|
|
12893
|
+
className: `w-4 h-4 ${active ? "opacity-90" : "text-gray-400"}`
|
|
12894
|
+
}
|
|
12895
|
+
)
|
|
12896
|
+
)), /* @__PURE__ */ React__default.createElement(DropdownMenuContent, { align: "end", className: "min-w-52" }, /* @__PURE__ */ React__default.createElement(
|
|
12897
|
+
DropdownMenuRadioGroup,
|
|
12898
|
+
{
|
|
12899
|
+
value,
|
|
12900
|
+
onValueChange: (next) => setValue(next)
|
|
12901
|
+
},
|
|
12902
|
+
/* @__PURE__ */ React__default.createElement(DropdownMenuRadioItem, { value: "all" }, "Any type"),
|
|
12903
|
+
/* @__PURE__ */ React__default.createElement(DropdownMenuSeparator, null),
|
|
12904
|
+
/* @__PURE__ */ React__default.createElement(DropdownMenuLabel, null, "Category"),
|
|
12905
|
+
Object.keys(MEDIA_CATEGORIES).map(
|
|
12906
|
+
(category) => /* @__PURE__ */ React__default.createElement(DropdownMenuRadioItem, { key: category, value: category }, TYPE_FILTER_LABELS[category])
|
|
12907
|
+
)
|
|
12908
|
+
)));
|
|
12909
|
+
};
|
|
12343
12910
|
const ViewModeToggle = ({ viewMode, setViewMode }) => {
|
|
12344
12911
|
const base = "relative flex items-center justify-center w-9 py-1.5 transition-colors ease-out duration-150";
|
|
12345
12912
|
const active = "bg-white text-tina-orange";
|
|
@@ -13591,7 +14158,7 @@ const FormModal = ({ plugin, close: close2 }) => {
|
|
|
13591
14158
|
const name = "tinacms";
|
|
13592
14159
|
const type = "module";
|
|
13593
14160
|
const typings = "dist/index.d.ts";
|
|
13594
|
-
const version = "3.
|
|
14161
|
+
const version = "3.13.0";
|
|
13595
14162
|
const main = "dist/index.js";
|
|
13596
14163
|
const module$1 = "./dist/index.js";
|
|
13597
14164
|
const exports$1 = { ".": "./dist/index.js", "./dist/client": "./dist/client.js", "./react": "./dist/react.js", "./dist/react": "./dist/react.js", "./tina-field": "./dist/tina-field.js", "./dist/tina-field": "./dist/tina-field.js", "./dist/rich-text": "./dist/rich-text/index.js", "./dist/rich-text/static": "./dist/rich-text/static.js", "./dist/rich-text/prism": "./dist/rich-text/prism.js" };
|
|
@@ -13599,8 +14166,8 @@ const files = ["dist"];
|
|
|
13599
14166
|
const buildConfig = { "entryPoints": ["src/index.ts", "src/rich-text/index.tsx", "src/rich-text/static.tsx", "src/rich-text/prism.tsx", "src/react.tsx", "src/tina-field.ts", { "name": "src/client.ts", "target": "node" }] };
|
|
13600
14167
|
const license = "Apache-2.0";
|
|
13601
14168
|
const scripts = { "types": "pnpm tsc && pnpm tsc-alias", "build": "tinacms-scripts build", "test": "vitest run", "test-watch": "vitest" };
|
|
13602
|
-
const dependencies = { "@ariakit/react": "catalog:", "@dnd-kit/core": "catalog:", "@dnd-kit/sortable": "catalog:", "@dnd-kit/utilities": "catalog:", "@floating-ui/dom": "catalog:", "@floating-ui/react-dom": "catalog:", "@graphql-inspector/core": "^6.2.1", "@radix-ui/react-dialog": "catalog:", "@radix-ui/react-dropdown-menu": "catalog:", "@radix-ui/react-popover": "catalog:", "@radix-ui/react-select": "catalog:", "@radix-ui/react-separator": "catalog:", "@radix-ui/react-slot": "catalog:", "@radix-ui/react-toolbar": "catalog:", "@radix-ui/react-tooltip": "catalog:", "@react-hook/window-size": "catalog:", "@tanstack/react-table": "^8.21.3", "@tinacms/bridge": "workspace:^", "@tinacms/mdx": "workspace:^", "@tinacms/schema-tools": "workspace:^", "@tinacms/search": "workspace:^", "@udecode/cmdk": "catalog:", "@udecode/cn": "catalog:", "@udecode/plate": "catalog:", "@udecode/plate-autoformat": "catalog:", "@udecode/plate-basic-marks": "catalog:", "@udecode/plate-block-quote": "catalog:", "@udecode/plate-break": "catalog:", "@udecode/plate-code-block": "catalog:", "@udecode/plate-combobox": "catalog:", "@udecode/plate-dnd": "catalog:", "@udecode/plate-floating": "catalog:", "@udecode/plate-heading": "catalog:", "@udecode/plate-highlight": "catalog:", "@udecode/plate-horizontal-rule": "catalog:", "@udecode/plate-indent-list": "catalog:", "@udecode/plate-link": "catalog:", "@udecode/plate-list": "catalog:", "@udecode/plate-node-id": "catalog:", "@udecode/plate-reset-node": "catalog:", "@udecode/plate-resizable": "catalog:", "@udecode/plate-selection": "catalog:", "@udecode/plate-slash-command": "catalog:", "@udecode/plate-table": "catalog:", "@udecode/plate-trailing-block": "catalog:", "class-variance-authority": "catalog:", "clsx": "catalog:", "cmdk": "catalog:", "color-string": "catalog:", "
|
|
13603
|
-
const devDependencies = { "@graphql-tools/utils": "catalog:", "@testing-library/dom": "catalog:", "@testing-library/jest-dom": "catalog:", "@testing-library/react": "catalog:", "@testing-library/user-event": "catalog:", "@tinacms/scripts": "workspace:*", "@types/atob": "catalog:", "@types/codemirror": "catalog:", "@types/color-string": "catalog:", "@types/node": "^22.13.1", "@types/prop-types": "catalog:", "@types/react": "^18.3.18", "@types/react-dom": "catalog:", "happy-dom": "catalog:", "identity-obj-proxy": "catalog:", "jest-file-snapshot": "^0.7.0", "lowlight": "catalog:", "next": "
|
|
14169
|
+
const dependencies = { "@ariakit/react": "catalog:", "@dnd-kit/core": "catalog:", "@dnd-kit/sortable": "catalog:", "@dnd-kit/utilities": "catalog:", "@floating-ui/dom": "catalog:", "@floating-ui/react-dom": "catalog:", "@graphql-inspector/core": "^6.2.1", "@radix-ui/react-dialog": "catalog:", "@radix-ui/react-dropdown-menu": "catalog:", "@radix-ui/react-popover": "catalog:", "@radix-ui/react-select": "catalog:", "@radix-ui/react-separator": "catalog:", "@radix-ui/react-slot": "catalog:", "@radix-ui/react-toolbar": "catalog:", "@radix-ui/react-tooltip": "catalog:", "@react-hook/window-size": "catalog:", "@tanstack/react-table": "^8.21.3", "@tinacms/bridge": "workspace:^", "@tinacms/mdx": "workspace:^", "@tinacms/schema-tools": "workspace:^", "@tinacms/search": "workspace:^", "@udecode/cmdk": "catalog:", "@udecode/cn": "catalog:", "@udecode/plate": "catalog:", "@udecode/plate-autoformat": "catalog:", "@udecode/plate-basic-marks": "catalog:", "@udecode/plate-block-quote": "catalog:", "@udecode/plate-break": "catalog:", "@udecode/plate-code-block": "catalog:", "@udecode/plate-combobox": "catalog:", "@udecode/plate-dnd": "catalog:", "@udecode/plate-floating": "catalog:", "@udecode/plate-heading": "catalog:", "@udecode/plate-highlight": "catalog:", "@udecode/plate-horizontal-rule": "catalog:", "@udecode/plate-indent-list": "catalog:", "@udecode/plate-link": "catalog:", "@udecode/plate-list": "catalog:", "@udecode/plate-node-id": "catalog:", "@udecode/plate-reset-node": "catalog:", "@udecode/plate-resizable": "catalog:", "@udecode/plate-selection": "catalog:", "@udecode/plate-slash-command": "catalog:", "@udecode/plate-table": "catalog:", "@udecode/plate-trailing-block": "catalog:", "class-variance-authority": "catalog:", "clsx": "catalog:", "cmdk": "catalog:", "color-string": "catalog:", "date-fns": "4.1.0", "es-toolkit": "^1.42.0", "final-form": "catalog:", "final-form-arrays": "catalog:", "final-form-set-field-data": "catalog:", "graphql": "15.8.0", "graphql-tag": "catalog:", "is-hotkey": "catalog:", "lucide-react": "catalog:", "mermaid": "catalog:", "posthog-js": "^1.347.1", "prism-react-renderer": "catalog:", "prop-types": "catalog:", "react-colorful": "catalog:", "react-day-picker": "^9.13.0", "react-dnd": "catalog:", "react-dnd-html5-backend": "catalog:", "react-dropzone": "catalog:", "react-final-form": "catalog:", "react-router-dom": "catalog:", "react-use": "catalog:", "tailwind-merge": "^2.6.0", "webfontloader": "catalog:", "yup": "^1.6.1", "zod": "catalog:" };
|
|
14170
|
+
const devDependencies = { "@graphql-tools/utils": "catalog:", "@testing-library/dom": "catalog:", "@testing-library/jest-dom": "catalog:", "@testing-library/react": "catalog:", "@testing-library/user-event": "catalog:", "@tinacms/scripts": "workspace:*", "@types/atob": "catalog:", "@types/codemirror": "catalog:", "@types/color-string": "catalog:", "@types/node": "^22.13.1", "@types/prop-types": "catalog:", "@types/react": "^18.3.18", "@types/react-dom": "catalog:", "happy-dom": "catalog:", "identity-obj-proxy": "catalog:", "jest-file-snapshot": "^0.7.0", "lowlight": "catalog:", "next": "15.5.21", "react": "^18.3.1", "react-dom": "^18.3.1", "react-is": "^18.3.1", "tsc-alias": "catalog:", "tslib": "catalog:", "typescript": "^5.7.3", "vite": "^5.4.14", "vitest": "^2.1.9" };
|
|
13604
14171
|
const peerDependencies = { "react": ">=16.14.0", "react-dom": ">=16.14.0" };
|
|
13605
14172
|
const publishConfig = { "registry": "https://registry.npmjs.org" };
|
|
13606
14173
|
const repository = { "url": "https://github.com/tinacms/tinacms.git", "directory": "packages/tinacms" };
|
|
@@ -13699,7 +14266,11 @@ const useGetEvents = (cms, cursor, existingEvents) => {
|
|
|
13699
14266
|
var _a, _b, _c, _d, _e;
|
|
13700
14267
|
let doFetchEvents = false;
|
|
13701
14268
|
if (!((_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.isCustomContentApi)) {
|
|
13702
|
-
|
|
14269
|
+
try {
|
|
14270
|
+
doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
|
|
14271
|
+
} catch {
|
|
14272
|
+
doFetchEvents = false;
|
|
14273
|
+
}
|
|
13703
14274
|
}
|
|
13704
14275
|
if (doFetchEvents) {
|
|
13705
14276
|
try {
|
|
@@ -13732,7 +14303,11 @@ function useSyncStatus(cms) {
|
|
|
13732
14303
|
var _a2, _b2, _c, _d, _e;
|
|
13733
14304
|
let doFetchEvents = false;
|
|
13734
14305
|
if (!((_b2 = (_a2 = cms.api) == null ? void 0 : _a2.tina) == null ? void 0 : _b2.isCustomContentApi)) {
|
|
13735
|
-
|
|
14306
|
+
try {
|
|
14307
|
+
doFetchEvents = await ((_e = (_d = (_c = cms.api) == null ? void 0 : _c.tina) == null ? void 0 : _d.authProvider) == null ? void 0 : _e.isAuthenticated());
|
|
14308
|
+
} catch {
|
|
14309
|
+
doFetchEvents = false;
|
|
14310
|
+
}
|
|
13736
14311
|
}
|
|
13737
14312
|
if (doFetchEvents) {
|
|
13738
14313
|
const { events } = await cms.api.tina.fetchEvents();
|
|
@@ -16256,34 +16831,6 @@ const BranchPreviewButton = (props) => {
|
|
|
16256
16831
|
/* @__PURE__ */ React.createElement(ExternalLink, { className: "h-5 w-auto" })
|
|
16257
16832
|
);
|
|
16258
16833
|
};
|
|
16259
|
-
function useLocalStorage(key, initialValue) {
|
|
16260
|
-
const [storedValue, setStoredValue] = React.useState(() => {
|
|
16261
|
-
try {
|
|
16262
|
-
const valueFromStorage = typeof window !== "undefined" && window.localStorage && window.localStorage.getItem(key);
|
|
16263
|
-
if (valueFromStorage != null) {
|
|
16264
|
-
return JSON.parse(valueFromStorage);
|
|
16265
|
-
}
|
|
16266
|
-
} catch (error) {
|
|
16267
|
-
}
|
|
16268
|
-
return initialValue;
|
|
16269
|
-
});
|
|
16270
|
-
React.useEffect(() => {
|
|
16271
|
-
const valueFromStorage = window.localStorage && window.localStorage.getItem(key);
|
|
16272
|
-
if (valueFromStorage != null && valueFromStorage != void 0) {
|
|
16273
|
-
setStoredValue(JSON.parse(valueFromStorage));
|
|
16274
|
-
}
|
|
16275
|
-
}, [key]);
|
|
16276
|
-
const setValue = (value) => {
|
|
16277
|
-
try {
|
|
16278
|
-
const valueToStore = value instanceof Function ? value(storedValue) : value;
|
|
16279
|
-
setStoredValue(valueToStore);
|
|
16280
|
-
localStorage.setItem(key, JSON.stringify(valueToStore));
|
|
16281
|
-
} catch (error) {
|
|
16282
|
-
console.log(error);
|
|
16283
|
-
}
|
|
16284
|
-
};
|
|
16285
|
-
return [storedValue, setValue];
|
|
16286
|
-
}
|
|
16287
16834
|
const CREATE_DOCUMENT_GQL = `#graphql
|
|
16288
16835
|
mutation($collection: String!, $relativePath: String!, $params: DocumentMutation!) {
|
|
16289
16836
|
createDocument(
|
|
@@ -16923,22 +17470,6 @@ const resolveSaveOptions = (lastChoice, disablePublish) => {
|
|
|
16923
17470
|
const menu = SAVE_CHOICE_ORDER.filter((choice) => choice !== main2);
|
|
16924
17471
|
return { main: main2, menu };
|
|
16925
17472
|
};
|
|
16926
|
-
const formatDefaultBranchName = (filePath, crudType) => {
|
|
16927
|
-
let result = filePath;
|
|
16928
|
-
const contentPrefix = "content/";
|
|
16929
|
-
if (result.startsWith(contentPrefix)) {
|
|
16930
|
-
result = result.substring(contentPrefix.length);
|
|
16931
|
-
}
|
|
16932
|
-
const lastDot = result.lastIndexOf(".");
|
|
16933
|
-
const lastSlash = Math.max(result.lastIndexOf("/"), result.lastIndexOf("\\"));
|
|
16934
|
-
if (lastDot > lastSlash && lastDot > 0) {
|
|
16935
|
-
result = result.slice(0, lastDot);
|
|
16936
|
-
}
|
|
16937
|
-
if (crudType === "delete") {
|
|
16938
|
-
result = `❌-${result}`;
|
|
16939
|
-
}
|
|
16940
|
-
return result;
|
|
16941
|
-
};
|
|
16942
17473
|
const CreateBranchModal = ({
|
|
16943
17474
|
close: close2,
|
|
16944
17475
|
safeSubmit,
|
|
@@ -16954,6 +17485,7 @@ const CreateBranchModal = ({
|
|
|
16954
17485
|
formatDefaultBranchName(path, crudType)
|
|
16955
17486
|
);
|
|
16956
17487
|
const [isBranchGuardChecking, setIsBranchGuardChecking] = React.useState(false);
|
|
17488
|
+
const normalizedBranchName = normalizeBranchName(newBranchName);
|
|
16957
17489
|
const branchGuardAbortRef = React.useRef(null);
|
|
16958
17490
|
const {
|
|
16959
17491
|
isExecuting,
|
|
@@ -16981,7 +17513,7 @@ const CreateBranchModal = ({
|
|
|
16981
17513
|
branchGuardAbortRef.current = abortController;
|
|
16982
17514
|
setIsBranchGuardChecking(true);
|
|
16983
17515
|
const baseBranch = decodeURIComponent(tinaApi.branch);
|
|
16984
|
-
const targetBranch = `tina/${
|
|
17516
|
+
const targetBranch = `tina/${normalizedBranchName}`;
|
|
16985
17517
|
const { baseBranchExists, targetBranchExists } = await checkBranchGuard(
|
|
16986
17518
|
tinaApi,
|
|
16987
17519
|
baseBranch,
|
|
@@ -17042,7 +17574,7 @@ const CreateBranchModal = ({
|
|
|
17042
17574
|
close2();
|
|
17043
17575
|
},
|
|
17044
17576
|
errorMessage,
|
|
17045
|
-
disabled:
|
|
17577
|
+
disabled: normalizedBranchName === "" || isBranchGuardChecking,
|
|
17046
17578
|
onBranchNameChange: (value) => {
|
|
17047
17579
|
abortBranchGuard();
|
|
17048
17580
|
reset();
|
|
@@ -17059,6 +17591,35 @@ const CreateBranchModal = ({
|
|
|
17059
17591
|
}
|
|
17060
17592
|
);
|
|
17061
17593
|
};
|
|
17594
|
+
const getInitials = (name2) => {
|
|
17595
|
+
const atIndex = name2.indexOf("@");
|
|
17596
|
+
const localPart = atIndex === -1 ? name2 : name2.slice(0, atIndex);
|
|
17597
|
+
return localPart.split(/[\s._-]+/).filter(Boolean).slice(0, 2).map((part) => [...part][0].toUpperCase()).join("");
|
|
17598
|
+
};
|
|
17599
|
+
const CommittingAs = () => {
|
|
17600
|
+
var _a, _b, _c;
|
|
17601
|
+
const cms = useCMS$1();
|
|
17602
|
+
const user = (_b = (_a = cms.api) == null ? void 0 : _a.tina) == null ? void 0 : _b.user;
|
|
17603
|
+
const author = typeof user === "object" && user !== null ? user : void 0;
|
|
17604
|
+
const mode = (_c = author == null ? void 0 : author.gitAuthoring) == null ? void 0 : _c.mode;
|
|
17605
|
+
if (mode !== "bot" && mode !== "user") {
|
|
17606
|
+
return null;
|
|
17607
|
+
}
|
|
17608
|
+
const authorName = mode === "bot" ? "TinaCloud bot" : author.fullName || author.email;
|
|
17609
|
+
if (!authorName) {
|
|
17610
|
+
return null;
|
|
17611
|
+
}
|
|
17612
|
+
return /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-3 mt-4 pt-4 border-t border-gray-100" }, /* @__PURE__ */ React.createElement("span", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-gray-100 text-gray-600 text-xs font-medium flex-shrink-0" }, getInitials(authorName)), /* @__PURE__ */ React.createElement("div", { className: "flex-1 min-w-0" }, /* @__PURE__ */ React.createElement("p", { className: "text-xs text-gray-500" }, "Committing as"), /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-700 font-medium truncate" }, authorName)), /* @__PURE__ */ React.createElement(
|
|
17613
|
+
"a",
|
|
17614
|
+
{
|
|
17615
|
+
className: "text-sm underline text-tina-orange-dark font-medium flex-shrink-0",
|
|
17616
|
+
href: cms.api.tina.gitSettingsLink,
|
|
17617
|
+
target: "_blank",
|
|
17618
|
+
rel: "noreferrer"
|
|
17619
|
+
},
|
|
17620
|
+
"Change"
|
|
17621
|
+
));
|
|
17622
|
+
};
|
|
17062
17623
|
const CreateBranchPromptModal = ({
|
|
17063
17624
|
branchName,
|
|
17064
17625
|
close: close2,
|
|
@@ -17068,7 +17629,8 @@ const CreateBranchPromptModal = ({
|
|
|
17068
17629
|
onCreateBranch,
|
|
17069
17630
|
onSaveToProtectedBranch,
|
|
17070
17631
|
showSaveOptions = false,
|
|
17071
|
-
disablePublish = false
|
|
17632
|
+
disablePublish = false,
|
|
17633
|
+
allowSaveToProtectedBranch = true
|
|
17072
17634
|
}) => {
|
|
17073
17635
|
const [lastChoice, setLastChoice] = useLocalStorage(
|
|
17074
17636
|
SAVE_CHOICE_KEY,
|
|
@@ -17115,7 +17677,7 @@ const CreateBranchPromptModal = ({
|
|
|
17115
17677
|
onBranchNameChange(e.target.value);
|
|
17116
17678
|
}
|
|
17117
17679
|
}
|
|
17118
|
-
))), /* @__PURE__ */ React.createElement(ModalActions, { align: "end" }, /* @__PURE__ */ React.createElement(
|
|
17680
|
+
), /* @__PURE__ */ React.createElement(CommittingAs, null))), /* @__PURE__ */ React.createElement(ModalActions, { align: "end" }, /* @__PURE__ */ React.createElement(
|
|
17119
17681
|
Button$2,
|
|
17120
17682
|
{
|
|
17121
17683
|
variant: "secondary",
|
|
@@ -17148,7 +17710,7 @@ const CreateBranchPromptModal = ({
|
|
|
17148
17710
|
},
|
|
17149
17711
|
/* @__PURE__ */ React.createElement(MainIcon, { className: "w-4 h-4 mr-1", style: { fill: "none" } }),
|
|
17150
17712
|
mainChoice.label
|
|
17151
|
-
) : /* @__PURE__ */ React.createElement(
|
|
17713
|
+
) : allowSaveToProtectedBranch ? /* @__PURE__ */ React.createElement(
|
|
17152
17714
|
DropdownButton,
|
|
17153
17715
|
{
|
|
17154
17716
|
variant: "primary",
|
|
@@ -17172,6 +17734,25 @@ const CreateBranchPromptModal = ({
|
|
|
17172
17734
|
}
|
|
17173
17735
|
),
|
|
17174
17736
|
"Save to a new branch"
|
|
17737
|
+
) : (
|
|
17738
|
+
// A plain button: the dropdown's only item is the one being dropped.
|
|
17739
|
+
/* @__PURE__ */ React.createElement(
|
|
17740
|
+
Button$2,
|
|
17741
|
+
{
|
|
17742
|
+
variant: "primary",
|
|
17743
|
+
className: "w-full sm:w-auto",
|
|
17744
|
+
disabled,
|
|
17745
|
+
onClick: () => onCreateBranch(false)
|
|
17746
|
+
},
|
|
17747
|
+
/* @__PURE__ */ React.createElement(
|
|
17748
|
+
GitBranchIcon,
|
|
17749
|
+
{
|
|
17750
|
+
className: "w-4 h-4 mr-1",
|
|
17751
|
+
style: { fill: "none" }
|
|
17752
|
+
}
|
|
17753
|
+
),
|
|
17754
|
+
"Save to a new branch"
|
|
17755
|
+
)
|
|
17175
17756
|
))));
|
|
17176
17757
|
};
|
|
17177
17758
|
const PrefixedTextField = ({
|
|
@@ -17200,6 +17781,7 @@ const BranchDeletedModal = ({
|
|
|
17200
17781
|
const cms = useCMS$1();
|
|
17201
17782
|
const tinaApi = cms.api.tina;
|
|
17202
17783
|
const [newBranchName, setNewBranchName] = React.useState("");
|
|
17784
|
+
const normalizedBranchName = normalizeBranchName(newBranchName);
|
|
17203
17785
|
const baseBranch = tinaApi.protectedBranches[0] || cms.api.tina.schema.config.config.repoProvider.defaultBranchName || "main";
|
|
17204
17786
|
const {
|
|
17205
17787
|
isExecuting,
|
|
@@ -17211,7 +17793,7 @@ const BranchDeletedModal = ({
|
|
|
17211
17793
|
} = useEditorialWorkflow();
|
|
17212
17794
|
const handleCreate = async () => {
|
|
17213
17795
|
const { success } = await executeWorkflow({
|
|
17214
|
-
branchName: `tina/${
|
|
17796
|
+
branchName: `tina/${normalizedBranchName}`,
|
|
17215
17797
|
baseBranch,
|
|
17216
17798
|
path,
|
|
17217
17799
|
values,
|
|
@@ -17258,7 +17840,7 @@ const BranchDeletedModal = ({
|
|
|
17258
17840
|
{
|
|
17259
17841
|
variant: "primary",
|
|
17260
17842
|
className: "w-full sm:w-auto",
|
|
17261
|
-
disabled: !
|
|
17843
|
+
disabled: !normalizedBranchName,
|
|
17262
17844
|
onClick: handleCreate
|
|
17263
17845
|
},
|
|
17264
17846
|
/* @__PURE__ */ React.createElement(
|
|
@@ -17523,6 +18105,10 @@ const FormBuilder = ({
|
|
|
17523
18105
|
setDeletedBranchModalOpen(true);
|
|
17524
18106
|
return;
|
|
17525
18107
|
}
|
|
18108
|
+
if (isSessionExpiredError(error)) {
|
|
18109
|
+
captureWorkflowChoice(false, errorMsg);
|
|
18110
|
+
return;
|
|
18111
|
+
}
|
|
17526
18112
|
captureEvent(SaveContentErrorEvent, {
|
|
17527
18113
|
documentPath: tinaForm.path,
|
|
17528
18114
|
error: errorMsg
|
|
@@ -18623,7 +19209,7 @@ function HeadingsMenu(props) {
|
|
|
18623
19209
|
className: "min-w-0 rounded-none rounded-bl rounded-br border-border"
|
|
18624
19210
|
},
|
|
18625
19211
|
/* @__PURE__ */ React__default.createElement(
|
|
18626
|
-
DropdownMenuRadioGroup,
|
|
19212
|
+
DropdownMenuRadioGroup$1,
|
|
18627
19213
|
{
|
|
18628
19214
|
className: "flex flex-col gap-0.5",
|
|
18629
19215
|
onValueChange: (type2) => {
|
|
@@ -18639,7 +19225,7 @@ function HeadingsMenu(props) {
|
|
|
18639
19225
|
}
|
|
18640
19226
|
return true;
|
|
18641
19227
|
}).map(({ icon: Icon, label, value: itemValue }) => /* @__PURE__ */ React__default.createElement(
|
|
18642
|
-
DropdownMenuRadioItem,
|
|
19228
|
+
DropdownMenuRadioItem$1,
|
|
18643
19229
|
{
|
|
18644
19230
|
className: "min-w-[180px]",
|
|
18645
19231
|
key: itemValue,
|
|
@@ -19395,549 +19981,6 @@ const useCreateEditor = ({
|
|
|
19395
19981
|
components
|
|
19396
19982
|
});
|
|
19397
19983
|
};
|
|
19398
|
-
const popoverVariants = cva(
|
|
19399
|
-
"z-[999999] w-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-hidden"
|
|
19400
|
-
);
|
|
19401
|
-
const inputVariants = cva(
|
|
19402
|
-
"flex h-[28px] w-full rounded-md border-none bg-transparent px-1.5 py-1 text-base placeholder:text-muted-foreground focus-visible:ring-transparent focus-visible:outline-none md:text-sm"
|
|
19403
|
-
);
|
|
19404
|
-
function LinkFloatingToolbar({
|
|
19405
|
-
state
|
|
19406
|
-
}) {
|
|
19407
|
-
const activeCommentId = usePluginOption({ key: "comment" }, "activeId");
|
|
19408
|
-
const activeSuggestionId = usePluginOption({ key: "suggestion" }, "activeId");
|
|
19409
|
-
const { api, editor } = useEditorPlugin(LinkPlugin);
|
|
19410
|
-
const isUrlValidator = usePluginOption(LinkPlugin, "isUrl");
|
|
19411
|
-
const [currentUrl, setCurrentUrl] = React.useState("");
|
|
19412
|
-
const [isValidUrl, setIsValidUrl] = React.useState(true);
|
|
19413
|
-
const handleUrlInput = React.useCallback(
|
|
19414
|
-
(e) => {
|
|
19415
|
-
const value = e.currentTarget.value;
|
|
19416
|
-
setCurrentUrl(value);
|
|
19417
|
-
if (value && isUrlValidator) {
|
|
19418
|
-
const valid = isUrlValidator(value);
|
|
19419
|
-
setIsValidUrl(valid);
|
|
19420
|
-
} else {
|
|
19421
|
-
setIsValidUrl(true);
|
|
19422
|
-
}
|
|
19423
|
-
},
|
|
19424
|
-
[isUrlValidator]
|
|
19425
|
-
);
|
|
19426
|
-
const floatingOptions = React.useMemo(() => {
|
|
19427
|
-
return {
|
|
19428
|
-
middleware: [
|
|
19429
|
-
offset(8),
|
|
19430
|
-
flip({
|
|
19431
|
-
fallbackPlacements: ["bottom-end", "top-start", "top-end"],
|
|
19432
|
-
padding: 12
|
|
19433
|
-
}),
|
|
19434
|
-
shift({ padding: 8, limiter: limitShift() })
|
|
19435
|
-
],
|
|
19436
|
-
placement: activeSuggestionId || activeCommentId ? "top-start" : "bottom-start"
|
|
19437
|
-
};
|
|
19438
|
-
}, [activeCommentId, activeSuggestionId]);
|
|
19439
|
-
const insertState = useFloatingLinkInsertState({
|
|
19440
|
-
...state,
|
|
19441
|
-
floatingOptions: {
|
|
19442
|
-
...floatingOptions,
|
|
19443
|
-
...state == null ? void 0 : state.floatingOptions
|
|
19444
|
-
}
|
|
19445
|
-
});
|
|
19446
|
-
const {
|
|
19447
|
-
hidden,
|
|
19448
|
-
props: insertProps,
|
|
19449
|
-
ref: insertRef,
|
|
19450
|
-
textInputProps
|
|
19451
|
-
} = useFloatingLinkInsert(insertState);
|
|
19452
|
-
const editState = useFloatingLinkEditState({
|
|
19453
|
-
...state,
|
|
19454
|
-
floatingOptions: {
|
|
19455
|
-
...floatingOptions,
|
|
19456
|
-
...state == null ? void 0 : state.floatingOptions
|
|
19457
|
-
}
|
|
19458
|
-
});
|
|
19459
|
-
const {
|
|
19460
|
-
editButtonProps,
|
|
19461
|
-
props: editProps,
|
|
19462
|
-
ref: editRef,
|
|
19463
|
-
unlinkButtonProps
|
|
19464
|
-
} = useFloatingLinkEdit(editState);
|
|
19465
|
-
const inputProps = useFormInputProps({
|
|
19466
|
-
preventDefaultOnEnterKeydown: true
|
|
19467
|
-
});
|
|
19468
|
-
if (hidden) return null;
|
|
19469
|
-
const input = /* @__PURE__ */ React.createElement(
|
|
19470
|
-
"div",
|
|
19471
|
-
{
|
|
19472
|
-
className: "z-[999999] flex w-[330px] flex-col relative",
|
|
19473
|
-
...inputProps
|
|
19474
|
-
},
|
|
19475
|
-
!isValidUrl && currentUrl && /* @__PURE__ */ React.createElement("div", { className: "absolute -top-16 left-0 right-0 z-[1000000] mb-2" }, /* @__PURE__ */ React.createElement(
|
|
19476
|
-
"div",
|
|
19477
|
-
{
|
|
19478
|
-
className: "bg-red-50 border border-red-200 rounded-md p-2 shadow-lg",
|
|
19479
|
-
role: "alert",
|
|
19480
|
-
"aria-live": "polite"
|
|
19481
|
-
},
|
|
19482
|
-
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement(CircleX, { className: "size-4 text-red-500 mr-2 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm text-red-700 text-wrap" }, "Invalid URL. Please prefix link with https:// or use a relative path like /about")),
|
|
19483
|
-
/* @__PURE__ */ React.createElement("div", { className: "absolute -bottom-1 left-4 w-2 h-2 bg-red-50 border-r border-b border-red-200 transform rotate-45" })
|
|
19484
|
-
)),
|
|
19485
|
-
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center pr-1 pl-2 text-muted-foreground" }, /* @__PURE__ */ React.createElement(Link, { className: "size-4" })), /* @__PURE__ */ React.createElement(
|
|
19486
|
-
FloatingLinkUrlInput,
|
|
19487
|
-
{
|
|
19488
|
-
className: inputVariants(),
|
|
19489
|
-
placeholder: "Paste link",
|
|
19490
|
-
"data-plate-focus": true,
|
|
19491
|
-
onInput: handleUrlInput
|
|
19492
|
-
}
|
|
19493
|
-
)),
|
|
19494
|
-
/* @__PURE__ */ React.createElement(Separator, { className: "my-1" }),
|
|
19495
|
-
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center pr-1 pl-2 text-muted-foreground" }, /* @__PURE__ */ React.createElement(Text, { className: "size-4" })), /* @__PURE__ */ React.createElement(
|
|
19496
|
-
"input",
|
|
19497
|
-
{
|
|
19498
|
-
className: inputVariants(),
|
|
19499
|
-
placeholder: "Text to display",
|
|
19500
|
-
"data-plate-focus": true,
|
|
19501
|
-
...textInputProps
|
|
19502
|
-
}
|
|
19503
|
-
)),
|
|
19504
|
-
/* @__PURE__ */ React.createElement(Separator, { className: "my-1" }),
|
|
19505
|
-
/* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-end gap-2 px-2 py-1" }, /* @__PURE__ */ React.createElement(
|
|
19506
|
-
"button",
|
|
19507
|
-
{
|
|
19508
|
-
type: "button",
|
|
19509
|
-
className: buttonVariants$2({ size: "sm", variant: "ghost" }),
|
|
19510
|
-
onClick: () => {
|
|
19511
|
-
api.floatingLink.hide();
|
|
19512
|
-
}
|
|
19513
|
-
},
|
|
19514
|
-
"Cancel"
|
|
19515
|
-
), /* @__PURE__ */ React.createElement(
|
|
19516
|
-
"button",
|
|
19517
|
-
{
|
|
19518
|
-
type: "button",
|
|
19519
|
-
className: buttonVariants$2({
|
|
19520
|
-
size: "sm",
|
|
19521
|
-
variant: "tinaPrimary"
|
|
19522
|
-
}),
|
|
19523
|
-
onClick: () => {
|
|
19524
|
-
if (isValidUrl && currentUrl) {
|
|
19525
|
-
submitFloatingLink(editor);
|
|
19526
|
-
}
|
|
19527
|
-
},
|
|
19528
|
-
disabled: !isValidUrl && !!currentUrl
|
|
19529
|
-
},
|
|
19530
|
-
"OK"
|
|
19531
|
-
))
|
|
19532
|
-
);
|
|
19533
|
-
const editContent = editState.isEditing ? input : /* @__PURE__ */ React.createElement("div", { className: "box-content flex items-center" }, /* @__PURE__ */ React.createElement(
|
|
19534
|
-
"button",
|
|
19535
|
-
{
|
|
19536
|
-
className: buttonVariants$2({ size: "sm", variant: "ghost" }),
|
|
19537
|
-
type: "button",
|
|
19538
|
-
...editButtonProps
|
|
19539
|
-
},
|
|
19540
|
-
"Edit link"
|
|
19541
|
-
), /* @__PURE__ */ React.createElement(Separator, { orientation: "vertical" }), /* @__PURE__ */ React.createElement(LinkOpenButton, null), /* @__PURE__ */ React.createElement(Separator, { orientation: "vertical" }), /* @__PURE__ */ React.createElement(
|
|
19542
|
-
"button",
|
|
19543
|
-
{
|
|
19544
|
-
className: buttonVariants$2({
|
|
19545
|
-
size: "icon",
|
|
19546
|
-
variant: "ghost"
|
|
19547
|
-
}),
|
|
19548
|
-
type: "button",
|
|
19549
|
-
...unlinkButtonProps
|
|
19550
|
-
},
|
|
19551
|
-
/* @__PURE__ */ React.createElement(Unlink, { width: 18 })
|
|
19552
|
-
));
|
|
19553
|
-
return /* @__PURE__ */ React.createElement(PortalBody, null, /* @__PURE__ */ React.createElement(
|
|
19554
|
-
"div",
|
|
19555
|
-
{
|
|
19556
|
-
ref: insertRef,
|
|
19557
|
-
className: popoverVariants(),
|
|
19558
|
-
...insertProps,
|
|
19559
|
-
style: {
|
|
19560
|
-
...insertProps.style,
|
|
19561
|
-
zIndex: 999999
|
|
19562
|
-
}
|
|
19563
|
-
},
|
|
19564
|
-
input
|
|
19565
|
-
), /* @__PURE__ */ React.createElement(
|
|
19566
|
-
"div",
|
|
19567
|
-
{
|
|
19568
|
-
ref: editRef,
|
|
19569
|
-
className: popoverVariants(),
|
|
19570
|
-
...editProps,
|
|
19571
|
-
style: { ...editProps.style, zIndex: 999999 }
|
|
19572
|
-
},
|
|
19573
|
-
editContent
|
|
19574
|
-
));
|
|
19575
|
-
}
|
|
19576
|
-
function LinkOpenButton() {
|
|
19577
|
-
const editor = useEditorRef();
|
|
19578
|
-
const selection = useEditorSelection();
|
|
19579
|
-
const attributes = React.useMemo(
|
|
19580
|
-
() => {
|
|
19581
|
-
const entry = editor.api.node({
|
|
19582
|
-
match: { type: editor.getType(LinkPlugin) }
|
|
19583
|
-
});
|
|
19584
|
-
if (!entry) {
|
|
19585
|
-
return {};
|
|
19586
|
-
}
|
|
19587
|
-
const [element] = entry;
|
|
19588
|
-
return getLinkAttributes(editor, element);
|
|
19589
|
-
},
|
|
19590
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
19591
|
-
[editor, selection]
|
|
19592
|
-
);
|
|
19593
|
-
return /* @__PURE__ */ React.createElement(
|
|
19594
|
-
"a",
|
|
19595
|
-
{
|
|
19596
|
-
...attributes,
|
|
19597
|
-
className: buttonVariants$2({
|
|
19598
|
-
size: "icon",
|
|
19599
|
-
variant: "ghost"
|
|
19600
|
-
}),
|
|
19601
|
-
onMouseOver: (e) => {
|
|
19602
|
-
e.stopPropagation();
|
|
19603
|
-
},
|
|
19604
|
-
"aria-label": "Open link in a new tab",
|
|
19605
|
-
target: "_blank"
|
|
19606
|
-
},
|
|
19607
|
-
/* @__PURE__ */ React.createElement(ExternalLink, { width: 18 })
|
|
19608
|
-
);
|
|
19609
|
-
}
|
|
19610
|
-
const protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
|
|
19611
|
-
const emailLintRE = /mailto:([^?\\]+)/;
|
|
19612
|
-
const telLintRE = /tel:([\d-]+)/;
|
|
19613
|
-
const localhostDomainRE = /^localhost[\d:?]*(?:[^\d:?]\S*)?$/;
|
|
19614
|
-
const nonLocalhostDomainRE = /^[^\s.]+\.\S{2,}$/;
|
|
19615
|
-
const localUrlRE = /^\/\S+/;
|
|
19616
|
-
const isUrl = (string) => {
|
|
19617
|
-
if (typeof string !== "string") {
|
|
19618
|
-
return false;
|
|
19619
|
-
}
|
|
19620
|
-
if (string.startsWith("#")) {
|
|
19621
|
-
return true;
|
|
19622
|
-
}
|
|
19623
|
-
const generalMatch = string.match(protocolAndDomainRE);
|
|
19624
|
-
const emailLinkMatch = string.match(emailLintRE);
|
|
19625
|
-
const telLinkMatch = string.match(telLintRE);
|
|
19626
|
-
const localUrlMatch = string.match(localUrlRE);
|
|
19627
|
-
if (emailLinkMatch || telLinkMatch || localUrlMatch) {
|
|
19628
|
-
return true;
|
|
19629
|
-
}
|
|
19630
|
-
if (generalMatch) {
|
|
19631
|
-
const everythingAfterProtocol = generalMatch[1];
|
|
19632
|
-
if (!everythingAfterProtocol) {
|
|
19633
|
-
return false;
|
|
19634
|
-
}
|
|
19635
|
-
try {
|
|
19636
|
-
new URL(string);
|
|
19637
|
-
} catch {
|
|
19638
|
-
return false;
|
|
19639
|
-
}
|
|
19640
|
-
return localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol);
|
|
19641
|
-
}
|
|
19642
|
-
return false;
|
|
19643
|
-
};
|
|
19644
|
-
const buildError = (element) => {
|
|
19645
|
-
return {
|
|
19646
|
-
message: element.message,
|
|
19647
|
-
position: element.position && {
|
|
19648
|
-
endColumn: element.position.end.column,
|
|
19649
|
-
startColumn: element.position.start.column,
|
|
19650
|
-
startLineNumber: element.position.start.line,
|
|
19651
|
-
endLineNumber: element.position.end.line
|
|
19652
|
-
}
|
|
19653
|
-
};
|
|
19654
|
-
};
|
|
19655
|
-
const buildErrorMessage = (element) => {
|
|
19656
|
-
if (!element) {
|
|
19657
|
-
return "";
|
|
19658
|
-
}
|
|
19659
|
-
const errorMessage = buildError(element);
|
|
19660
|
-
const message = errorMessage ? `${errorMessage.message}${errorMessage.position ? ` at line: ${errorMessage.position.startLineNumber}, column: ${errorMessage.position.startColumn}` : ""}` : null;
|
|
19661
|
-
return message;
|
|
19662
|
-
};
|
|
19663
|
-
const ELEMENT_INVALID_MARKDOWN = "invalid_markdown";
|
|
19664
|
-
const createInvalidMarkdownPlugin = createPlatePlugin({
|
|
19665
|
-
key: ELEMENT_INVALID_MARKDOWN,
|
|
19666
|
-
options: {
|
|
19667
|
-
isElement: true,
|
|
19668
|
-
isVoid: true,
|
|
19669
|
-
isInline: false
|
|
19670
|
-
},
|
|
19671
|
-
node: {
|
|
19672
|
-
component: InvalidMarkdownElement
|
|
19673
|
-
}
|
|
19674
|
-
});
|
|
19675
|
-
function InvalidMarkdownElement({
|
|
19676
|
-
attributes,
|
|
19677
|
-
element,
|
|
19678
|
-
children
|
|
19679
|
-
}) {
|
|
19680
|
-
return /* @__PURE__ */ React__default.createElement("div", { ...attributes }, /* @__PURE__ */ React__default.createElement(ErrorMessage, { error: element }), children);
|
|
19681
|
-
}
|
|
19682
|
-
function ErrorMessage({ error }) {
|
|
19683
|
-
const message = buildErrorMessage(error);
|
|
19684
|
-
const { setRawMode } = useEditorContext();
|
|
19685
|
-
return /* @__PURE__ */ React__default.createElement("div", { contentEditable: false, className: "bg-red-50 sm:rounded-lg" }, /* @__PURE__ */ React__default.createElement("div", { className: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg leading-6 font-medium text-red-800" }, "❌ Error parsing markdown"), /* @__PURE__ */ React__default.createElement("div", { className: "mt-2 max-w-xl text-sm text-red-800 space-y-4" }, /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement("p", null, "To fix these errors, edit the content in raw-mode."), /* @__PURE__ */ React__default.createElement(
|
|
19686
|
-
"button",
|
|
19687
|
-
{
|
|
19688
|
-
type: "button",
|
|
19689
|
-
onClick: () => setRawMode(true),
|
|
19690
|
-
className: "rounded-l border-r-0 shadow rounded bg-white cursor-pointer relative inline-flex items-center px-2 py-2 border border-gray-200 hover:text-white text-sm font-medium transition-all ease-out duration-150 hover:bg-gray-500 focus:z-10 focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"
|
|
19691
|
-
},
|
|
19692
|
-
"Switch to raw-mode"
|
|
19693
|
-
))));
|
|
19694
|
-
}
|
|
19695
|
-
const useCustomFloatingToolbarState = ({
|
|
19696
|
-
editorId,
|
|
19697
|
-
floatingOptions,
|
|
19698
|
-
focusedEditorId,
|
|
19699
|
-
hideToolbar,
|
|
19700
|
-
showWhenReadOnly
|
|
19701
|
-
}) => {
|
|
19702
|
-
const editor = useEditorRef();
|
|
19703
|
-
const selectionExpanded = useEditorSelector(
|
|
19704
|
-
() => editor.api.isExpanded(),
|
|
19705
|
-
[]
|
|
19706
|
-
);
|
|
19707
|
-
const selectionText = useEditorSelector(() => editor.api.string(), []);
|
|
19708
|
-
const readOnly = useEditorReadOnly();
|
|
19709
|
-
const focused = useFocused();
|
|
19710
|
-
const [open, setOpen] = React__default.useState(false);
|
|
19711
|
-
const [waitForCollapsedSelection, setWaitForCollapsedSelection] = React__default.useState(false);
|
|
19712
|
-
const [mousedown, setMousedown] = React__default.useState(false);
|
|
19713
|
-
const floating = useVirtualFloating(
|
|
19714
|
-
mergeProps(
|
|
19715
|
-
{
|
|
19716
|
-
open,
|
|
19717
|
-
getBoundingClientRect: () => getSelectionBoundingClientRect(editor),
|
|
19718
|
-
onOpenChange: setOpen
|
|
19719
|
-
},
|
|
19720
|
-
floatingOptions
|
|
19721
|
-
)
|
|
19722
|
-
);
|
|
19723
|
-
return {
|
|
19724
|
-
editorId,
|
|
19725
|
-
floating,
|
|
19726
|
-
focused,
|
|
19727
|
-
focusedEditorId,
|
|
19728
|
-
hideToolbar,
|
|
19729
|
-
mousedown,
|
|
19730
|
-
open,
|
|
19731
|
-
readOnly,
|
|
19732
|
-
selectionExpanded,
|
|
19733
|
-
selectionText,
|
|
19734
|
-
setMousedown,
|
|
19735
|
-
setOpen,
|
|
19736
|
-
setWaitForCollapsedSelection,
|
|
19737
|
-
showWhenReadOnly,
|
|
19738
|
-
waitForCollapsedSelection
|
|
19739
|
-
};
|
|
19740
|
-
};
|
|
19741
|
-
const useCustomFloatingToolbar = ({
|
|
19742
|
-
editorId,
|
|
19743
|
-
floating,
|
|
19744
|
-
focusedEditorId,
|
|
19745
|
-
hideToolbar,
|
|
19746
|
-
mousedown,
|
|
19747
|
-
open,
|
|
19748
|
-
readOnly,
|
|
19749
|
-
selectionExpanded,
|
|
19750
|
-
selectionText,
|
|
19751
|
-
setMousedown,
|
|
19752
|
-
setOpen,
|
|
19753
|
-
setWaitForCollapsedSelection,
|
|
19754
|
-
showWhenReadOnly,
|
|
19755
|
-
waitForCollapsedSelection
|
|
19756
|
-
}) => {
|
|
19757
|
-
React__default.useEffect(() => {
|
|
19758
|
-
if (!(editorId === focusedEditorId)) {
|
|
19759
|
-
setWaitForCollapsedSelection(true);
|
|
19760
|
-
}
|
|
19761
|
-
if (!selectionExpanded) {
|
|
19762
|
-
setWaitForCollapsedSelection(false);
|
|
19763
|
-
}
|
|
19764
|
-
}, [
|
|
19765
|
-
editorId,
|
|
19766
|
-
focusedEditorId,
|
|
19767
|
-
selectionExpanded,
|
|
19768
|
-
setWaitForCollapsedSelection
|
|
19769
|
-
]);
|
|
19770
|
-
React__default.useEffect(() => {
|
|
19771
|
-
const mouseup = () => setMousedown(false);
|
|
19772
|
-
const mousedown2 = () => setMousedown(true);
|
|
19773
|
-
document.addEventListener("mouseup", mouseup);
|
|
19774
|
-
document.addEventListener("mousedown", mousedown2);
|
|
19775
|
-
return () => {
|
|
19776
|
-
document.removeEventListener("mouseup", mouseup);
|
|
19777
|
-
document.removeEventListener("mousedown", mousedown2);
|
|
19778
|
-
};
|
|
19779
|
-
}, []);
|
|
19780
|
-
React__default.useEffect(() => {
|
|
19781
|
-
if (!selectionExpanded || !selectionText || mousedown && !open || hideToolbar || readOnly && !showWhenReadOnly) {
|
|
19782
|
-
setOpen(false);
|
|
19783
|
-
} else if (selectionText && selectionExpanded && (!waitForCollapsedSelection || readOnly)) {
|
|
19784
|
-
setOpen(true);
|
|
19785
|
-
}
|
|
19786
|
-
}, [
|
|
19787
|
-
setOpen,
|
|
19788
|
-
editorId,
|
|
19789
|
-
focusedEditorId,
|
|
19790
|
-
hideToolbar,
|
|
19791
|
-
showWhenReadOnly,
|
|
19792
|
-
selectionExpanded,
|
|
19793
|
-
selectionText,
|
|
19794
|
-
mousedown,
|
|
19795
|
-
waitForCollapsedSelection,
|
|
19796
|
-
open,
|
|
19797
|
-
readOnly
|
|
19798
|
-
]);
|
|
19799
|
-
const { update } = floating;
|
|
19800
|
-
useEditorSelector(() => {
|
|
19801
|
-
update == null ? void 0 : update();
|
|
19802
|
-
}, [update]);
|
|
19803
|
-
const clickOutsideRef = useOnClickOutside(
|
|
19804
|
-
() => {
|
|
19805
|
-
setOpen(false);
|
|
19806
|
-
},
|
|
19807
|
-
{
|
|
19808
|
-
ignoreClass: "ignore-click-outside/toolbar"
|
|
19809
|
-
}
|
|
19810
|
-
);
|
|
19811
|
-
return {
|
|
19812
|
-
clickOutsideRef,
|
|
19813
|
-
hidden: !open,
|
|
19814
|
-
props: {
|
|
19815
|
-
style: floating.style
|
|
19816
|
-
},
|
|
19817
|
-
ref: floating.refs.setFloating
|
|
19818
|
-
};
|
|
19819
|
-
};
|
|
19820
|
-
const FloatingToolbar = withRef(({ children, state, ...props }, propRef) => {
|
|
19821
|
-
const editorId = useEditorRef();
|
|
19822
|
-
const focusedEditorId = useEventEditorValue("focus");
|
|
19823
|
-
const test = useCustomFloatingToolbarState({
|
|
19824
|
-
editorId: editorId.id,
|
|
19825
|
-
focusedEditorId,
|
|
19826
|
-
...state,
|
|
19827
|
-
floatingOptions: {
|
|
19828
|
-
middleware: [
|
|
19829
|
-
offset(12),
|
|
19830
|
-
flip({
|
|
19831
|
-
fallbackPlacements: [
|
|
19832
|
-
"top-start",
|
|
19833
|
-
"top-end",
|
|
19834
|
-
"bottom-start",
|
|
19835
|
-
"bottom-end"
|
|
19836
|
-
],
|
|
19837
|
-
padding: 12
|
|
19838
|
-
})
|
|
19839
|
-
],
|
|
19840
|
-
placement: "top",
|
|
19841
|
-
...state == null ? void 0 : state.floatingOptions
|
|
19842
|
-
}
|
|
19843
|
-
});
|
|
19844
|
-
const {
|
|
19845
|
-
hidden,
|
|
19846
|
-
props: rootProps,
|
|
19847
|
-
ref: floatingRef
|
|
19848
|
-
} = useCustomFloatingToolbar(test);
|
|
19849
|
-
const ref = useComposedRef$1(propRef, floatingRef);
|
|
19850
|
-
if (hidden) return null;
|
|
19851
|
-
return /* @__PURE__ */ React__default.createElement(PortalBody, null, /* @__PURE__ */ React__default.createElement(
|
|
19852
|
-
Toolbar,
|
|
19853
|
-
{
|
|
19854
|
-
className: cn$1(
|
|
19855
|
-
"absolute z-[10799] whitespace-nowrap border bg-popover px-1 opacity-100 shadow-md print:hidden rounded-md"
|
|
19856
|
-
),
|
|
19857
|
-
...props,
|
|
19858
|
-
...rootProps,
|
|
19859
|
-
ref
|
|
19860
|
-
},
|
|
19861
|
-
children
|
|
19862
|
-
));
|
|
19863
|
-
});
|
|
19864
|
-
function TurnIntoDropdownMenu(props) {
|
|
19865
|
-
const { headingLevels } = useToolbarContext();
|
|
19866
|
-
const items = [
|
|
19867
|
-
paragraphItem,
|
|
19868
|
-
...headingLevels.map((level) => headingItemsByLevel[level])
|
|
19869
|
-
];
|
|
19870
|
-
const value = useEditorSelector((editor2) => {
|
|
19871
|
-
let initialNodeType = ParagraphPlugin.key;
|
|
19872
|
-
let allNodesMatchInitialNodeType = false;
|
|
19873
|
-
const codeBlockEntries = editor2.api.nodes({
|
|
19874
|
-
match: (n) => editor2.api.isBlock(n),
|
|
19875
|
-
mode: "highest"
|
|
19876
|
-
});
|
|
19877
|
-
const nodes = Array.from(codeBlockEntries);
|
|
19878
|
-
if (nodes.length > 0) {
|
|
19879
|
-
initialNodeType = nodes[0][0].type;
|
|
19880
|
-
allNodesMatchInitialNodeType = nodes.every(([node]) => {
|
|
19881
|
-
const type2 = (node == null ? void 0 : node.type) || ParagraphPlugin.key;
|
|
19882
|
-
return type2 === initialNodeType;
|
|
19883
|
-
});
|
|
19884
|
-
}
|
|
19885
|
-
return allNodesMatchInitialNodeType ? initialNodeType : ParagraphPlugin.key;
|
|
19886
|
-
}, []);
|
|
19887
|
-
const editor = useEditorRef();
|
|
19888
|
-
const openState = useOpenState();
|
|
19889
|
-
const selectedItem = getHeadingItem(value) ?? paragraphItem;
|
|
19890
|
-
const { icon: SelectedItemIcon, label: selectedItemLabel } = selectedItem;
|
|
19891
|
-
const editorState = useEditorState();
|
|
19892
|
-
const userInTable = helpers.isNodeActive(editorState, TablePlugin.key);
|
|
19893
|
-
if (userInTable) return null;
|
|
19894
|
-
return /* @__PURE__ */ React__default.createElement(DropdownMenu$1, { modal: false, ...openState, ...props }, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement(
|
|
19895
|
-
ToolbarButton,
|
|
19896
|
-
{
|
|
19897
|
-
className: "lg:min-w-[130px]",
|
|
19898
|
-
isDropdown: true,
|
|
19899
|
-
showArrow: true,
|
|
19900
|
-
pressed: openState.open,
|
|
19901
|
-
tooltip: "Turn into"
|
|
19902
|
-
},
|
|
19903
|
-
/* @__PURE__ */ React__default.createElement("span", { className: "" }, selectedItemLabel)
|
|
19904
|
-
)), /* @__PURE__ */ React__default.createElement(DropdownMenuContent$1, { align: "start", className: "min-w-0" }, /* @__PURE__ */ React__default.createElement(DropdownMenuLabel, null, "Turn into"), /* @__PURE__ */ React__default.createElement(
|
|
19905
|
-
DropdownMenuRadioGroup,
|
|
19906
|
-
{
|
|
19907
|
-
className: "flex flex-col gap-0.5",
|
|
19908
|
-
onValueChange: (type2) => {
|
|
19909
|
-
if (type2 === "ul" || type2 === "ol") {
|
|
19910
|
-
toggleList(editor, { type: type2 });
|
|
19911
|
-
} else {
|
|
19912
|
-
unwrapList(editor);
|
|
19913
|
-
editor.tf.toggleBlock(type2);
|
|
19914
|
-
}
|
|
19915
|
-
editor.tf.collapse();
|
|
19916
|
-
editor.tf.focus();
|
|
19917
|
-
},
|
|
19918
|
-
value
|
|
19919
|
-
},
|
|
19920
|
-
items.map(({ icon: Icon, label, value: itemValue }) => /* @__PURE__ */ React__default.createElement(
|
|
19921
|
-
DropdownMenuRadioItem,
|
|
19922
|
-
{
|
|
19923
|
-
className: "min-w-[180px]",
|
|
19924
|
-
key: itemValue,
|
|
19925
|
-
value: itemValue
|
|
19926
|
-
},
|
|
19927
|
-
/* @__PURE__ */ React__default.createElement(Icon, { className: "mr-2 size-5" }),
|
|
19928
|
-
label
|
|
19929
|
-
))
|
|
19930
|
-
)));
|
|
19931
|
-
}
|
|
19932
|
-
function FloatingToolbarButtons() {
|
|
19933
|
-
return /* @__PURE__ */ React__default.createElement("div", { className: "rounded-md" }, /* @__PURE__ */ React__default.createElement(TurnIntoDropdownMenu, null));
|
|
19934
|
-
}
|
|
19935
|
-
const FloatingToolbarPlugin = createPlatePlugin({
|
|
19936
|
-
key: "floating-toolbar",
|
|
19937
|
-
render: {
|
|
19938
|
-
afterEditable: () => /* @__PURE__ */ React__default.createElement(FloatingToolbar, null, /* @__PURE__ */ React__default.createElement(FloatingToolbarButtons, null))
|
|
19939
|
-
}
|
|
19940
|
-
});
|
|
19941
19984
|
function _1c(hljs) {
|
|
19942
19985
|
const UNDERSCORE_IDENT_RE = "[A-Za-zА-Яа-яёЁ_][A-Za-zА-Яа-яёЁ_0-9]+";
|
|
19943
19986
|
const v7_keywords = "далее ";
|
|
@@ -70583,6 +70626,252 @@ class HastEmitter {
|
|
|
70583
70626
|
return "";
|
|
70584
70627
|
}
|
|
70585
70628
|
}
|
|
70629
|
+
const popoverVariants = cva(
|
|
70630
|
+
"z-[999999] w-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-hidden"
|
|
70631
|
+
);
|
|
70632
|
+
const inputVariants = cva(
|
|
70633
|
+
"flex h-[28px] w-full rounded-md border-none bg-transparent px-1.5 py-1 text-base placeholder:text-muted-foreground focus-visible:ring-transparent focus-visible:outline-none md:text-sm"
|
|
70634
|
+
);
|
|
70635
|
+
function LinkFloatingToolbar({
|
|
70636
|
+
state
|
|
70637
|
+
}) {
|
|
70638
|
+
const activeCommentId = usePluginOption({ key: "comment" }, "activeId");
|
|
70639
|
+
const activeSuggestionId = usePluginOption({ key: "suggestion" }, "activeId");
|
|
70640
|
+
const { api, editor } = useEditorPlugin(LinkPlugin);
|
|
70641
|
+
const isUrlValidator = usePluginOption(LinkPlugin, "isUrl");
|
|
70642
|
+
const [currentUrl, setCurrentUrl] = React.useState("");
|
|
70643
|
+
const [isValidUrl, setIsValidUrl] = React.useState(true);
|
|
70644
|
+
const handleUrlInput = React.useCallback(
|
|
70645
|
+
(e) => {
|
|
70646
|
+
const value = e.currentTarget.value;
|
|
70647
|
+
setCurrentUrl(value);
|
|
70648
|
+
if (value && isUrlValidator) {
|
|
70649
|
+
const valid = isUrlValidator(value);
|
|
70650
|
+
setIsValidUrl(valid);
|
|
70651
|
+
} else {
|
|
70652
|
+
setIsValidUrl(true);
|
|
70653
|
+
}
|
|
70654
|
+
},
|
|
70655
|
+
[isUrlValidator]
|
|
70656
|
+
);
|
|
70657
|
+
const floatingOptions = React.useMemo(() => {
|
|
70658
|
+
return {
|
|
70659
|
+
middleware: [
|
|
70660
|
+
offset(8),
|
|
70661
|
+
flip({
|
|
70662
|
+
fallbackPlacements: ["bottom-end", "top-start", "top-end"],
|
|
70663
|
+
padding: 12
|
|
70664
|
+
}),
|
|
70665
|
+
shift({ padding: 8, limiter: limitShift() })
|
|
70666
|
+
],
|
|
70667
|
+
placement: activeSuggestionId || activeCommentId ? "top-start" : "bottom-start"
|
|
70668
|
+
};
|
|
70669
|
+
}, [activeCommentId, activeSuggestionId]);
|
|
70670
|
+
const insertState = useFloatingLinkInsertState({
|
|
70671
|
+
...state,
|
|
70672
|
+
floatingOptions: {
|
|
70673
|
+
...floatingOptions,
|
|
70674
|
+
...state == null ? void 0 : state.floatingOptions
|
|
70675
|
+
}
|
|
70676
|
+
});
|
|
70677
|
+
const {
|
|
70678
|
+
hidden,
|
|
70679
|
+
props: insertProps,
|
|
70680
|
+
ref: insertRef,
|
|
70681
|
+
textInputProps
|
|
70682
|
+
} = useFloatingLinkInsert(insertState);
|
|
70683
|
+
const editState = useFloatingLinkEditState({
|
|
70684
|
+
...state,
|
|
70685
|
+
floatingOptions: {
|
|
70686
|
+
...floatingOptions,
|
|
70687
|
+
...state == null ? void 0 : state.floatingOptions
|
|
70688
|
+
}
|
|
70689
|
+
});
|
|
70690
|
+
const {
|
|
70691
|
+
editButtonProps,
|
|
70692
|
+
props: editProps,
|
|
70693
|
+
ref: editRef,
|
|
70694
|
+
unlinkButtonProps
|
|
70695
|
+
} = useFloatingLinkEdit(editState);
|
|
70696
|
+
const inputProps = useFormInputProps({
|
|
70697
|
+
preventDefaultOnEnterKeydown: true
|
|
70698
|
+
});
|
|
70699
|
+
if (hidden) return null;
|
|
70700
|
+
const input = /* @__PURE__ */ React.createElement(
|
|
70701
|
+
"div",
|
|
70702
|
+
{
|
|
70703
|
+
className: "z-[999999] flex w-[330px] flex-col relative",
|
|
70704
|
+
...inputProps
|
|
70705
|
+
},
|
|
70706
|
+
!isValidUrl && currentUrl && /* @__PURE__ */ React.createElement("div", { className: "absolute -top-16 left-0 right-0 z-[1000000] mb-2" }, /* @__PURE__ */ React.createElement(
|
|
70707
|
+
"div",
|
|
70708
|
+
{
|
|
70709
|
+
className: "bg-red-50 border border-red-200 rounded-md p-2 shadow-lg",
|
|
70710
|
+
role: "alert",
|
|
70711
|
+
"aria-live": "polite"
|
|
70712
|
+
},
|
|
70713
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement(CircleX, { className: "size-4 text-red-500 mr-2 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm text-red-700 text-wrap" }, "Invalid URL. Please prefix link with https:// or use a relative path like /about")),
|
|
70714
|
+
/* @__PURE__ */ React.createElement("div", { className: "absolute -bottom-1 left-4 w-2 h-2 bg-red-50 border-r border-b border-red-200 transform rotate-45" })
|
|
70715
|
+
)),
|
|
70716
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center pr-1 pl-2 text-muted-foreground" }, /* @__PURE__ */ React.createElement(Link, { className: "size-4" })), /* @__PURE__ */ React.createElement(
|
|
70717
|
+
FloatingLinkUrlInput,
|
|
70718
|
+
{
|
|
70719
|
+
className: inputVariants(),
|
|
70720
|
+
placeholder: "Paste link",
|
|
70721
|
+
"data-plate-focus": true,
|
|
70722
|
+
onInput: handleUrlInput
|
|
70723
|
+
}
|
|
70724
|
+
)),
|
|
70725
|
+
/* @__PURE__ */ React.createElement(Separator, { className: "my-1" }),
|
|
70726
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center pr-1 pl-2 text-muted-foreground" }, /* @__PURE__ */ React.createElement(Text, { className: "size-4" })), /* @__PURE__ */ React.createElement(
|
|
70727
|
+
"input",
|
|
70728
|
+
{
|
|
70729
|
+
className: inputVariants(),
|
|
70730
|
+
placeholder: "Text to display",
|
|
70731
|
+
"data-plate-focus": true,
|
|
70732
|
+
...textInputProps
|
|
70733
|
+
}
|
|
70734
|
+
)),
|
|
70735
|
+
/* @__PURE__ */ React.createElement(Separator, { className: "my-1" }),
|
|
70736
|
+
/* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-end gap-2 px-2 py-1" }, /* @__PURE__ */ React.createElement(
|
|
70737
|
+
"button",
|
|
70738
|
+
{
|
|
70739
|
+
type: "button",
|
|
70740
|
+
className: buttonVariants$2({ size: "sm", variant: "ghost" }),
|
|
70741
|
+
onClick: () => {
|
|
70742
|
+
api.floatingLink.hide();
|
|
70743
|
+
}
|
|
70744
|
+
},
|
|
70745
|
+
"Cancel"
|
|
70746
|
+
), /* @__PURE__ */ React.createElement(
|
|
70747
|
+
"button",
|
|
70748
|
+
{
|
|
70749
|
+
type: "button",
|
|
70750
|
+
className: buttonVariants$2({
|
|
70751
|
+
size: "sm",
|
|
70752
|
+
variant: "tinaPrimary"
|
|
70753
|
+
}),
|
|
70754
|
+
onClick: () => {
|
|
70755
|
+
if (isValidUrl && currentUrl) {
|
|
70756
|
+
submitFloatingLink(editor);
|
|
70757
|
+
}
|
|
70758
|
+
},
|
|
70759
|
+
disabled: !isValidUrl && !!currentUrl
|
|
70760
|
+
},
|
|
70761
|
+
"OK"
|
|
70762
|
+
))
|
|
70763
|
+
);
|
|
70764
|
+
const editContent = editState.isEditing ? input : /* @__PURE__ */ React.createElement("div", { className: "box-content flex items-center" }, /* @__PURE__ */ React.createElement(
|
|
70765
|
+
"button",
|
|
70766
|
+
{
|
|
70767
|
+
className: buttonVariants$2({ size: "sm", variant: "ghost" }),
|
|
70768
|
+
type: "button",
|
|
70769
|
+
...editButtonProps
|
|
70770
|
+
},
|
|
70771
|
+
"Edit link"
|
|
70772
|
+
), /* @__PURE__ */ React.createElement(Separator, { orientation: "vertical" }), /* @__PURE__ */ React.createElement(LinkOpenButton, null), /* @__PURE__ */ React.createElement(Separator, { orientation: "vertical" }), /* @__PURE__ */ React.createElement(
|
|
70773
|
+
"button",
|
|
70774
|
+
{
|
|
70775
|
+
className: buttonVariants$2({
|
|
70776
|
+
size: "icon",
|
|
70777
|
+
variant: "ghost"
|
|
70778
|
+
}),
|
|
70779
|
+
type: "button",
|
|
70780
|
+
...unlinkButtonProps
|
|
70781
|
+
},
|
|
70782
|
+
/* @__PURE__ */ React.createElement(Unlink, { width: 18 })
|
|
70783
|
+
));
|
|
70784
|
+
return /* @__PURE__ */ React.createElement(PortalBody, null, /* @__PURE__ */ React.createElement(
|
|
70785
|
+
"div",
|
|
70786
|
+
{
|
|
70787
|
+
ref: insertRef,
|
|
70788
|
+
className: popoverVariants(),
|
|
70789
|
+
...insertProps,
|
|
70790
|
+
style: {
|
|
70791
|
+
...insertProps.style,
|
|
70792
|
+
zIndex: 999999
|
|
70793
|
+
}
|
|
70794
|
+
},
|
|
70795
|
+
input
|
|
70796
|
+
), /* @__PURE__ */ React.createElement(
|
|
70797
|
+
"div",
|
|
70798
|
+
{
|
|
70799
|
+
ref: editRef,
|
|
70800
|
+
className: popoverVariants(),
|
|
70801
|
+
...editProps,
|
|
70802
|
+
style: { ...editProps.style, zIndex: 999999 }
|
|
70803
|
+
},
|
|
70804
|
+
editContent
|
|
70805
|
+
));
|
|
70806
|
+
}
|
|
70807
|
+
function LinkOpenButton() {
|
|
70808
|
+
const editor = useEditorRef();
|
|
70809
|
+
const selection = useEditorSelection();
|
|
70810
|
+
const attributes = React.useMemo(
|
|
70811
|
+
() => {
|
|
70812
|
+
const entry = editor.api.node({
|
|
70813
|
+
match: { type: editor.getType(LinkPlugin) }
|
|
70814
|
+
});
|
|
70815
|
+
if (!entry) {
|
|
70816
|
+
return {};
|
|
70817
|
+
}
|
|
70818
|
+
const [element] = entry;
|
|
70819
|
+
return getLinkAttributes(editor, element);
|
|
70820
|
+
},
|
|
70821
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70822
|
+
[editor, selection]
|
|
70823
|
+
);
|
|
70824
|
+
return /* @__PURE__ */ React.createElement(
|
|
70825
|
+
"a",
|
|
70826
|
+
{
|
|
70827
|
+
...attributes,
|
|
70828
|
+
className: buttonVariants$2({
|
|
70829
|
+
size: "icon",
|
|
70830
|
+
variant: "ghost"
|
|
70831
|
+
}),
|
|
70832
|
+
onMouseOver: (e) => {
|
|
70833
|
+
e.stopPropagation();
|
|
70834
|
+
},
|
|
70835
|
+
"aria-label": "Open link in a new tab",
|
|
70836
|
+
target: "_blank"
|
|
70837
|
+
},
|
|
70838
|
+
/* @__PURE__ */ React.createElement(ExternalLink, { width: 18 })
|
|
70839
|
+
);
|
|
70840
|
+
}
|
|
70841
|
+
const protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
|
|
70842
|
+
const emailLintRE = /mailto:([^?\\]+)/;
|
|
70843
|
+
const telLintRE = /tel:([\d-]+)/;
|
|
70844
|
+
const localhostDomainRE = /^localhost[\d:?]*(?:[^\d:?]\S*)?$/;
|
|
70845
|
+
const nonLocalhostDomainRE = /^[^\s.]+\.\S{2,}$/;
|
|
70846
|
+
const localUrlRE = /^\/\S+/;
|
|
70847
|
+
const isUrl = (string) => {
|
|
70848
|
+
if (typeof string !== "string") {
|
|
70849
|
+
return false;
|
|
70850
|
+
}
|
|
70851
|
+
if (string.startsWith("#")) {
|
|
70852
|
+
return true;
|
|
70853
|
+
}
|
|
70854
|
+
const generalMatch = string.match(protocolAndDomainRE);
|
|
70855
|
+
const emailLinkMatch = string.match(emailLintRE);
|
|
70856
|
+
const telLinkMatch = string.match(telLintRE);
|
|
70857
|
+
const localUrlMatch = string.match(localUrlRE);
|
|
70858
|
+
if (emailLinkMatch || telLinkMatch || localUrlMatch) {
|
|
70859
|
+
return true;
|
|
70860
|
+
}
|
|
70861
|
+
if (generalMatch) {
|
|
70862
|
+
const everythingAfterProtocol = generalMatch[1];
|
|
70863
|
+
if (!everythingAfterProtocol) {
|
|
70864
|
+
return false;
|
|
70865
|
+
}
|
|
70866
|
+
try {
|
|
70867
|
+
new URL(string);
|
|
70868
|
+
} catch {
|
|
70869
|
+
return false;
|
|
70870
|
+
}
|
|
70871
|
+
return localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol);
|
|
70872
|
+
}
|
|
70873
|
+
return false;
|
|
70874
|
+
};
|
|
70586
70875
|
const createHTMLBlockPlugin = createPlatePlugin({
|
|
70587
70876
|
key: "html",
|
|
70588
70877
|
node: {
|
|
@@ -70599,18 +70888,26 @@ const createHTMLInlinePlugin = createPlatePlugin({
|
|
|
70599
70888
|
isInline: true
|
|
70600
70889
|
}
|
|
70601
70890
|
});
|
|
70602
|
-
const
|
|
70603
|
-
const
|
|
70604
|
-
key
|
|
70891
|
+
const KEY_HARD_BREAK = "tina-hard-break";
|
|
70892
|
+
const NO_HARD_BREAK = [
|
|
70893
|
+
CodeBlockPlugin.key,
|
|
70894
|
+
TableCellPlugin.key,
|
|
70895
|
+
TableCellHeaderPlugin.key
|
|
70896
|
+
];
|
|
70897
|
+
const createHardBreakPlugin = createPlatePlugin({
|
|
70898
|
+
key: KEY_HARD_BREAK,
|
|
70605
70899
|
handlers: {
|
|
70606
70900
|
onKeyDown: ({ editor, event }) => {
|
|
70607
70901
|
var _a;
|
|
70608
|
-
if (event.key !== "Enter") return;
|
|
70609
|
-
const
|
|
70902
|
+
if (event.key !== "Enter" || event.metaKey || event.ctrlKey) return;
|
|
70903
|
+
const inBlockquote = editor.api.above({
|
|
70610
70904
|
match: { type: BlockquotePlugin.key }
|
|
70611
70905
|
});
|
|
70612
|
-
if (!
|
|
70906
|
+
if (!event.shiftKey && !inBlockquote) return;
|
|
70907
|
+
if (editor.api.some({ match: { type: NO_HARD_BREAK } })) return;
|
|
70908
|
+
if (!editor.selection) return;
|
|
70613
70909
|
event.preventDefault();
|
|
70910
|
+
if (editor.api.isExpanded()) editor.tf.delete();
|
|
70614
70911
|
const cursorPosition = (_a = editor.selection) == null ? void 0 : _a.focus;
|
|
70615
70912
|
if (!cursorPosition) return;
|
|
70616
70913
|
editor.tf.insertNodes(
|
|
@@ -70638,6 +70935,303 @@ const createBreakPlugin = createPlatePlugin({
|
|
|
70638
70935
|
}
|
|
70639
70936
|
}
|
|
70640
70937
|
});
|
|
70938
|
+
const buildError = (element) => {
|
|
70939
|
+
return {
|
|
70940
|
+
message: element.message,
|
|
70941
|
+
position: element.position && {
|
|
70942
|
+
endColumn: element.position.end.column,
|
|
70943
|
+
startColumn: element.position.start.column,
|
|
70944
|
+
startLineNumber: element.position.start.line,
|
|
70945
|
+
endLineNumber: element.position.end.line
|
|
70946
|
+
}
|
|
70947
|
+
};
|
|
70948
|
+
};
|
|
70949
|
+
const buildErrorMessage = (element) => {
|
|
70950
|
+
if (!element) {
|
|
70951
|
+
return "";
|
|
70952
|
+
}
|
|
70953
|
+
const errorMessage = buildError(element);
|
|
70954
|
+
const message = errorMessage ? `${errorMessage.message}${errorMessage.position ? ` at line: ${errorMessage.position.startLineNumber}, column: ${errorMessage.position.startColumn}` : ""}` : null;
|
|
70955
|
+
return message;
|
|
70956
|
+
};
|
|
70957
|
+
const ELEMENT_INVALID_MARKDOWN = "invalid_markdown";
|
|
70958
|
+
const createInvalidMarkdownPlugin = createPlatePlugin({
|
|
70959
|
+
key: ELEMENT_INVALID_MARKDOWN,
|
|
70960
|
+
options: {
|
|
70961
|
+
isElement: true,
|
|
70962
|
+
isVoid: true,
|
|
70963
|
+
isInline: false
|
|
70964
|
+
},
|
|
70965
|
+
node: {
|
|
70966
|
+
component: InvalidMarkdownElement
|
|
70967
|
+
}
|
|
70968
|
+
});
|
|
70969
|
+
function InvalidMarkdownElement({
|
|
70970
|
+
attributes,
|
|
70971
|
+
element,
|
|
70972
|
+
children
|
|
70973
|
+
}) {
|
|
70974
|
+
return /* @__PURE__ */ React__default.createElement("div", { ...attributes }, /* @__PURE__ */ React__default.createElement(ErrorMessage, { error: element }), children);
|
|
70975
|
+
}
|
|
70976
|
+
function ErrorMessage({ error }) {
|
|
70977
|
+
const message = buildErrorMessage(error);
|
|
70978
|
+
const { setRawMode } = useEditorContext();
|
|
70979
|
+
return /* @__PURE__ */ React__default.createElement("div", { contentEditable: false, className: "bg-red-50 sm:rounded-lg" }, /* @__PURE__ */ React__default.createElement("div", { className: "px-4 py-5 sm:p-6" }, /* @__PURE__ */ React__default.createElement("h3", { className: "text-lg leading-6 font-medium text-red-800" }, "❌ Error parsing markdown"), /* @__PURE__ */ React__default.createElement("div", { className: "mt-2 max-w-xl text-sm text-red-800 space-y-4" }, /* @__PURE__ */ React__default.createElement("p", null, message), /* @__PURE__ */ React__default.createElement("p", null, "To fix these errors, edit the content in raw-mode."), /* @__PURE__ */ React__default.createElement(
|
|
70980
|
+
"button",
|
|
70981
|
+
{
|
|
70982
|
+
type: "button",
|
|
70983
|
+
onClick: () => setRawMode(true),
|
|
70984
|
+
className: "rounded-l border-r-0 shadow rounded bg-white cursor-pointer relative inline-flex items-center px-2 py-2 border border-gray-200 hover:text-white text-sm font-medium transition-all ease-out duration-150 hover:bg-gray-500 focus:z-10 focus:outline-none focus:ring-1 focus:ring-gray-500 focus:border-gray-500"
|
|
70985
|
+
},
|
|
70986
|
+
"Switch to raw-mode"
|
|
70987
|
+
))));
|
|
70988
|
+
}
|
|
70989
|
+
const useCustomFloatingToolbarState = ({
|
|
70990
|
+
editorId,
|
|
70991
|
+
floatingOptions,
|
|
70992
|
+
focusedEditorId,
|
|
70993
|
+
hideToolbar,
|
|
70994
|
+
showWhenReadOnly
|
|
70995
|
+
}) => {
|
|
70996
|
+
const editor = useEditorRef();
|
|
70997
|
+
const selectionExpanded = useEditorSelector(
|
|
70998
|
+
() => editor.api.isExpanded(),
|
|
70999
|
+
[]
|
|
71000
|
+
);
|
|
71001
|
+
const selectionText = useEditorSelector(() => editor.api.string(), []);
|
|
71002
|
+
const readOnly = useEditorReadOnly();
|
|
71003
|
+
const focused = useFocused();
|
|
71004
|
+
const [open, setOpen] = React__default.useState(false);
|
|
71005
|
+
const [waitForCollapsedSelection, setWaitForCollapsedSelection] = React__default.useState(false);
|
|
71006
|
+
const [mousedown, setMousedown] = React__default.useState(false);
|
|
71007
|
+
const floating = useVirtualFloating(
|
|
71008
|
+
mergeProps(
|
|
71009
|
+
{
|
|
71010
|
+
open,
|
|
71011
|
+
getBoundingClientRect: () => getSelectionBoundingClientRect(editor),
|
|
71012
|
+
onOpenChange: setOpen
|
|
71013
|
+
},
|
|
71014
|
+
floatingOptions
|
|
71015
|
+
)
|
|
71016
|
+
);
|
|
71017
|
+
return {
|
|
71018
|
+
editorId,
|
|
71019
|
+
floating,
|
|
71020
|
+
focused,
|
|
71021
|
+
focusedEditorId,
|
|
71022
|
+
hideToolbar,
|
|
71023
|
+
mousedown,
|
|
71024
|
+
open,
|
|
71025
|
+
readOnly,
|
|
71026
|
+
selectionExpanded,
|
|
71027
|
+
selectionText,
|
|
71028
|
+
setMousedown,
|
|
71029
|
+
setOpen,
|
|
71030
|
+
setWaitForCollapsedSelection,
|
|
71031
|
+
showWhenReadOnly,
|
|
71032
|
+
waitForCollapsedSelection
|
|
71033
|
+
};
|
|
71034
|
+
};
|
|
71035
|
+
const useCustomFloatingToolbar = ({
|
|
71036
|
+
editorId,
|
|
71037
|
+
floating,
|
|
71038
|
+
focusedEditorId,
|
|
71039
|
+
hideToolbar,
|
|
71040
|
+
mousedown,
|
|
71041
|
+
open,
|
|
71042
|
+
readOnly,
|
|
71043
|
+
selectionExpanded,
|
|
71044
|
+
selectionText,
|
|
71045
|
+
setMousedown,
|
|
71046
|
+
setOpen,
|
|
71047
|
+
setWaitForCollapsedSelection,
|
|
71048
|
+
showWhenReadOnly,
|
|
71049
|
+
waitForCollapsedSelection
|
|
71050
|
+
}) => {
|
|
71051
|
+
React__default.useEffect(() => {
|
|
71052
|
+
if (!(editorId === focusedEditorId)) {
|
|
71053
|
+
setWaitForCollapsedSelection(true);
|
|
71054
|
+
}
|
|
71055
|
+
if (!selectionExpanded) {
|
|
71056
|
+
setWaitForCollapsedSelection(false);
|
|
71057
|
+
}
|
|
71058
|
+
}, [
|
|
71059
|
+
editorId,
|
|
71060
|
+
focusedEditorId,
|
|
71061
|
+
selectionExpanded,
|
|
71062
|
+
setWaitForCollapsedSelection
|
|
71063
|
+
]);
|
|
71064
|
+
React__default.useEffect(() => {
|
|
71065
|
+
const mouseup = () => setMousedown(false);
|
|
71066
|
+
const mousedown2 = () => setMousedown(true);
|
|
71067
|
+
document.addEventListener("mouseup", mouseup);
|
|
71068
|
+
document.addEventListener("mousedown", mousedown2);
|
|
71069
|
+
return () => {
|
|
71070
|
+
document.removeEventListener("mouseup", mouseup);
|
|
71071
|
+
document.removeEventListener("mousedown", mousedown2);
|
|
71072
|
+
};
|
|
71073
|
+
}, []);
|
|
71074
|
+
React__default.useEffect(() => {
|
|
71075
|
+
if (!selectionExpanded || !selectionText || mousedown && !open || hideToolbar || readOnly && !showWhenReadOnly) {
|
|
71076
|
+
setOpen(false);
|
|
71077
|
+
} else if (selectionText && selectionExpanded && (!waitForCollapsedSelection || readOnly)) {
|
|
71078
|
+
setOpen(true);
|
|
71079
|
+
}
|
|
71080
|
+
}, [
|
|
71081
|
+
setOpen,
|
|
71082
|
+
editorId,
|
|
71083
|
+
focusedEditorId,
|
|
71084
|
+
hideToolbar,
|
|
71085
|
+
showWhenReadOnly,
|
|
71086
|
+
selectionExpanded,
|
|
71087
|
+
selectionText,
|
|
71088
|
+
mousedown,
|
|
71089
|
+
waitForCollapsedSelection,
|
|
71090
|
+
open,
|
|
71091
|
+
readOnly
|
|
71092
|
+
]);
|
|
71093
|
+
const { update } = floating;
|
|
71094
|
+
useEditorSelector(() => {
|
|
71095
|
+
update == null ? void 0 : update();
|
|
71096
|
+
}, [update]);
|
|
71097
|
+
const clickOutsideRef = useOnClickOutside(
|
|
71098
|
+
() => {
|
|
71099
|
+
setOpen(false);
|
|
71100
|
+
},
|
|
71101
|
+
{
|
|
71102
|
+
ignoreClass: "ignore-click-outside/toolbar"
|
|
71103
|
+
}
|
|
71104
|
+
);
|
|
71105
|
+
return {
|
|
71106
|
+
clickOutsideRef,
|
|
71107
|
+
hidden: !open,
|
|
71108
|
+
props: {
|
|
71109
|
+
style: floating.style
|
|
71110
|
+
},
|
|
71111
|
+
ref: floating.refs.setFloating
|
|
71112
|
+
};
|
|
71113
|
+
};
|
|
71114
|
+
const FloatingToolbar = withRef(({ children, state, ...props }, propRef) => {
|
|
71115
|
+
const editorId = useEditorRef();
|
|
71116
|
+
const focusedEditorId = useEventEditorValue("focus");
|
|
71117
|
+
const test = useCustomFloatingToolbarState({
|
|
71118
|
+
editorId: editorId.id,
|
|
71119
|
+
focusedEditorId,
|
|
71120
|
+
...state,
|
|
71121
|
+
floatingOptions: {
|
|
71122
|
+
middleware: [
|
|
71123
|
+
offset(12),
|
|
71124
|
+
flip({
|
|
71125
|
+
fallbackPlacements: [
|
|
71126
|
+
"top-start",
|
|
71127
|
+
"top-end",
|
|
71128
|
+
"bottom-start",
|
|
71129
|
+
"bottom-end"
|
|
71130
|
+
],
|
|
71131
|
+
padding: 12
|
|
71132
|
+
})
|
|
71133
|
+
],
|
|
71134
|
+
placement: "top",
|
|
71135
|
+
...state == null ? void 0 : state.floatingOptions
|
|
71136
|
+
}
|
|
71137
|
+
});
|
|
71138
|
+
const {
|
|
71139
|
+
hidden,
|
|
71140
|
+
props: rootProps,
|
|
71141
|
+
ref: floatingRef
|
|
71142
|
+
} = useCustomFloatingToolbar(test);
|
|
71143
|
+
const ref = useComposedRef$1(propRef, floatingRef);
|
|
71144
|
+
if (hidden) return null;
|
|
71145
|
+
return /* @__PURE__ */ React__default.createElement(PortalBody, null, /* @__PURE__ */ React__default.createElement(
|
|
71146
|
+
Toolbar,
|
|
71147
|
+
{
|
|
71148
|
+
className: cn$1(
|
|
71149
|
+
"absolute z-[10799] whitespace-nowrap border bg-popover px-1 opacity-100 shadow-md print:hidden rounded-md"
|
|
71150
|
+
),
|
|
71151
|
+
...props,
|
|
71152
|
+
...rootProps,
|
|
71153
|
+
ref
|
|
71154
|
+
},
|
|
71155
|
+
children
|
|
71156
|
+
));
|
|
71157
|
+
});
|
|
71158
|
+
function TurnIntoDropdownMenu(props) {
|
|
71159
|
+
const { headingLevels } = useToolbarContext();
|
|
71160
|
+
const items = [
|
|
71161
|
+
paragraphItem,
|
|
71162
|
+
...headingLevels.map((level) => headingItemsByLevel[level])
|
|
71163
|
+
];
|
|
71164
|
+
const value = useEditorSelector((editor2) => {
|
|
71165
|
+
let initialNodeType = ParagraphPlugin.key;
|
|
71166
|
+
let allNodesMatchInitialNodeType = false;
|
|
71167
|
+
const codeBlockEntries = editor2.api.nodes({
|
|
71168
|
+
match: (n) => editor2.api.isBlock(n),
|
|
71169
|
+
mode: "highest"
|
|
71170
|
+
});
|
|
71171
|
+
const nodes = Array.from(codeBlockEntries);
|
|
71172
|
+
if (nodes.length > 0) {
|
|
71173
|
+
initialNodeType = nodes[0][0].type;
|
|
71174
|
+
allNodesMatchInitialNodeType = nodes.every(([node]) => {
|
|
71175
|
+
const type2 = (node == null ? void 0 : node.type) || ParagraphPlugin.key;
|
|
71176
|
+
return type2 === initialNodeType;
|
|
71177
|
+
});
|
|
71178
|
+
}
|
|
71179
|
+
return allNodesMatchInitialNodeType ? initialNodeType : ParagraphPlugin.key;
|
|
71180
|
+
}, []);
|
|
71181
|
+
const editor = useEditorRef();
|
|
71182
|
+
const openState = useOpenState();
|
|
71183
|
+
const selectedItem = getHeadingItem(value) ?? paragraphItem;
|
|
71184
|
+
const { icon: SelectedItemIcon, label: selectedItemLabel } = selectedItem;
|
|
71185
|
+
const editorState = useEditorState();
|
|
71186
|
+
const userInTable = helpers.isNodeActive(editorState, TablePlugin.key);
|
|
71187
|
+
if (userInTable) return null;
|
|
71188
|
+
return /* @__PURE__ */ React__default.createElement(DropdownMenu$1, { modal: false, ...openState, ...props }, /* @__PURE__ */ React__default.createElement(DropdownMenuTrigger$1, { asChild: true }, /* @__PURE__ */ React__default.createElement(
|
|
71189
|
+
ToolbarButton,
|
|
71190
|
+
{
|
|
71191
|
+
className: "lg:min-w-[130px]",
|
|
71192
|
+
isDropdown: true,
|
|
71193
|
+
showArrow: true,
|
|
71194
|
+
pressed: openState.open,
|
|
71195
|
+
tooltip: "Turn into"
|
|
71196
|
+
},
|
|
71197
|
+
/* @__PURE__ */ React__default.createElement("span", { className: "" }, selectedItemLabel)
|
|
71198
|
+
)), /* @__PURE__ */ React__default.createElement(DropdownMenuContent$1, { align: "start", className: "min-w-0" }, /* @__PURE__ */ React__default.createElement(DropdownMenuLabel$1, null, "Turn into"), /* @__PURE__ */ React__default.createElement(
|
|
71199
|
+
DropdownMenuRadioGroup$1,
|
|
71200
|
+
{
|
|
71201
|
+
className: "flex flex-col gap-0.5",
|
|
71202
|
+
onValueChange: (type2) => {
|
|
71203
|
+
if (type2 === "ul" || type2 === "ol") {
|
|
71204
|
+
toggleList(editor, { type: type2 });
|
|
71205
|
+
} else {
|
|
71206
|
+
unwrapList(editor);
|
|
71207
|
+
editor.tf.toggleBlock(type2);
|
|
71208
|
+
}
|
|
71209
|
+
editor.tf.collapse();
|
|
71210
|
+
editor.tf.focus();
|
|
71211
|
+
},
|
|
71212
|
+
value
|
|
71213
|
+
},
|
|
71214
|
+
items.map(({ icon: Icon, label, value: itemValue }) => /* @__PURE__ */ React__default.createElement(
|
|
71215
|
+
DropdownMenuRadioItem$1,
|
|
71216
|
+
{
|
|
71217
|
+
className: "min-w-[180px]",
|
|
71218
|
+
key: itemValue,
|
|
71219
|
+
value: itemValue
|
|
71220
|
+
},
|
|
71221
|
+
/* @__PURE__ */ React__default.createElement(Icon, { className: "mr-2 size-5" }),
|
|
71222
|
+
label
|
|
71223
|
+
))
|
|
71224
|
+
)));
|
|
71225
|
+
}
|
|
71226
|
+
function FloatingToolbarButtons() {
|
|
71227
|
+
return /* @__PURE__ */ React__default.createElement("div", { className: "rounded-md" }, /* @__PURE__ */ React__default.createElement(TurnIntoDropdownMenu, null));
|
|
71228
|
+
}
|
|
71229
|
+
const FloatingToolbarPlugin = createPlatePlugin({
|
|
71230
|
+
key: "floating-toolbar",
|
|
71231
|
+
render: {
|
|
71232
|
+
afterEditable: () => /* @__PURE__ */ React__default.createElement(FloatingToolbar, null, /* @__PURE__ */ React__default.createElement(FloatingToolbarButtons, null))
|
|
71233
|
+
}
|
|
71234
|
+
});
|
|
70641
71235
|
[
|
|
70642
71236
|
HEADING_KEYS.h1,
|
|
70643
71237
|
HEADING_KEYS.h2,
|
|
@@ -70702,7 +71296,7 @@ const createEditorPlugins = ({
|
|
|
70702
71296
|
createImgPlugin,
|
|
70703
71297
|
createHTMLBlockPlugin,
|
|
70704
71298
|
createHTMLInlinePlugin,
|
|
70705
|
-
|
|
71299
|
+
createHardBreakPlugin,
|
|
70706
71300
|
createInvalidMarkdownPlugin,
|
|
70707
71301
|
CorrectNodeBehaviorPlugin,
|
|
70708
71302
|
ClearHighlightOnEnterPlugin,
|
|
@@ -70801,6 +71395,8 @@ const createEditorPlugins = ({
|
|
|
70801
71395
|
]
|
|
70802
71396
|
}
|
|
70803
71397
|
}),
|
|
71398
|
+
// Only reached where `createHardBreakPlugin` bails (code blocks, table
|
|
71399
|
+
// cells) — everywhere else it has already inserted a `break` element.
|
|
70804
71400
|
SoftBreakPlugin.configure({
|
|
70805
71401
|
options: {
|
|
70806
71402
|
rules: [
|
|
@@ -70981,6 +71577,7 @@ const MediaWorkflowOverlay = () => {
|
|
|
70981
71577
|
phase: "confirming",
|
|
70982
71578
|
branchName: event.branchName,
|
|
70983
71579
|
baseBranch: event.baseBranch,
|
|
71580
|
+
allowSaveToProtectedBranch: event.allowSaveToProtectedBranch,
|
|
70984
71581
|
onConfirm: event.onConfirm,
|
|
70985
71582
|
onCancel: event.onCancel,
|
|
70986
71583
|
onSaveToProtectedBranch: event.onSaveToProtectedBranch
|
|
@@ -71033,7 +71630,7 @@ const MediaWorkflowOverlay = () => {
|
|
|
71033
71630
|
if (state.phase !== "confirming") return;
|
|
71034
71631
|
const confirmState = state;
|
|
71035
71632
|
const branchName = confirmState.branchName;
|
|
71036
|
-
const targetBranch = `tina/${branchName}`;
|
|
71633
|
+
const targetBranch = `tina/${normalizeBranchName(branchName)}`;
|
|
71037
71634
|
abortPreflight();
|
|
71038
71635
|
const abortController = new AbortController();
|
|
71039
71636
|
preflightAbortRef.current = abortController;
|
|
@@ -71101,7 +71698,7 @@ const MediaWorkflowOverlay = () => {
|
|
|
71101
71698
|
state.onCancel();
|
|
71102
71699
|
setState({ phase: "idle" });
|
|
71103
71700
|
},
|
|
71104
|
-
disabled: state.branchName === "" || state.isChecking,
|
|
71701
|
+
disabled: normalizeBranchName(state.branchName) === "" || state.isChecking,
|
|
71105
71702
|
errorMessage: state.errorMessage,
|
|
71106
71703
|
onBranchNameChange: (branchName) => {
|
|
71107
71704
|
abortPreflight();
|
|
@@ -71115,6 +71712,7 @@ const MediaWorkflowOverlay = () => {
|
|
|
71115
71712
|
);
|
|
71116
71713
|
},
|
|
71117
71714
|
onCreateBranch: handleCreateBranch,
|
|
71715
|
+
allowSaveToProtectedBranch: state.allowSaveToProtectedBranch,
|
|
71118
71716
|
onSaveToProtectedBranch: () => {
|
|
71119
71717
|
abortPreflight();
|
|
71120
71718
|
state.onSaveToProtectedBranch();
|
|
@@ -71304,6 +71902,14 @@ const DefaultSessionProvider = ({
|
|
|
71304
71902
|
children
|
|
71305
71903
|
}) => /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children);
|
|
71306
71904
|
class AbstractAuthProvider {
|
|
71905
|
+
constructor() {
|
|
71906
|
+
/**
|
|
71907
|
+
* Turns a tokened 401 into the auth wall re-arming. The Client assigns this
|
|
71908
|
+
* automatically; AbstractAuthProvider.fetchWithToken invokes it. A provider
|
|
71909
|
+
* that implements its own fetchWithToken must invoke it itself.
|
|
71910
|
+
*/
|
|
71911
|
+
__publicField(this, "sessionExpiredListener");
|
|
71912
|
+
}
|
|
71307
71913
|
/**
|
|
71308
71914
|
* Wraps the normal fetch function with same API but adds the authorization header token.
|
|
71309
71915
|
*
|
|
@@ -71314,16 +71920,24 @@ class AbstractAuthProvider {
|
|
|
71314
71920
|
* @param init fetch function init
|
|
71315
71921
|
*/
|
|
71316
71922
|
async fetchWithToken(input, init) {
|
|
71923
|
+
var _a;
|
|
71317
71924
|
const headers = (init == null ? void 0 : init.headers) || {};
|
|
71318
|
-
const
|
|
71319
|
-
const accessToken = (token == null ? void 0 : token.access_token) ?? (token == null ? void 0 : token.id_token);
|
|
71925
|
+
const accessToken = await this.getAccessToken();
|
|
71320
71926
|
if (accessToken) {
|
|
71321
71927
|
headers["Authorization"] = "Bearer " + accessToken;
|
|
71322
71928
|
}
|
|
71323
|
-
|
|
71929
|
+
const res = await fetch(input, {
|
|
71324
71930
|
...init || {},
|
|
71325
71931
|
headers: new Headers(headers)
|
|
71326
71932
|
});
|
|
71933
|
+
if (res.status === 401 && accessToken) {
|
|
71934
|
+
(_a = this.sessionExpiredListener) == null ? void 0 : _a.call(this);
|
|
71935
|
+
}
|
|
71936
|
+
return res;
|
|
71937
|
+
}
|
|
71938
|
+
async getAccessToken() {
|
|
71939
|
+
const token = await this.getToken();
|
|
71940
|
+
return (token == null ? void 0 : token.access_token) ?? (token == null ? void 0 : token.id_token) ?? null;
|
|
71327
71941
|
}
|
|
71328
71942
|
async authorize(context) {
|
|
71329
71943
|
return this.getToken();
|
|
@@ -71362,6 +71976,7 @@ class TinaCloudAuthProvider extends AbstractAuthProvider {
|
|
|
71362
71976
|
__publicField(this, "frontendUrl");
|
|
71363
71977
|
__publicField(this, "token");
|
|
71364
71978
|
// used with memory storage
|
|
71979
|
+
__publicField(this, "hasWarnedNoSession", false);
|
|
71365
71980
|
__publicField(this, "setToken");
|
|
71366
71981
|
__publicField(this, "getToken");
|
|
71367
71982
|
this.frontendUrl = frontendUrl;
|
|
@@ -71430,16 +72045,36 @@ class TinaCloudAuthProvider extends AbstractAuthProvider {
|
|
|
71430
72045
|
}
|
|
71431
72046
|
const url = `${this.identityApiUrl}/v2/apps/${this.clientId}/currentUser`;
|
|
71432
72047
|
try {
|
|
71433
|
-
|
|
71434
|
-
|
|
71435
|
-
|
|
72048
|
+
if (!await this.getAccessToken()) {
|
|
72049
|
+
if (!this.hasWarnedNoSession) {
|
|
72050
|
+
this.hasWarnedNoSession = true;
|
|
72051
|
+
console.warn(
|
|
72052
|
+
"TinaCMS: no TinaCloud session found. If login fails, check the console inside the login popup window for the underlying error."
|
|
72053
|
+
);
|
|
72054
|
+
}
|
|
72055
|
+
return null;
|
|
72056
|
+
}
|
|
72057
|
+
let res;
|
|
72058
|
+
try {
|
|
72059
|
+
res = await this.fetchWithToken(url, { method: "GET" });
|
|
72060
|
+
} catch (networkError) {
|
|
72061
|
+
console.warn("TinaCMS: session check failed, retrying.", networkError);
|
|
72062
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
72063
|
+
res = await this.fetchWithToken(url, { method: "GET" });
|
|
72064
|
+
}
|
|
71436
72065
|
const val = await res.json();
|
|
71437
72066
|
if (!res.status.toString().startsWith("2")) {
|
|
71438
|
-
console.error(
|
|
72067
|
+
console.error(
|
|
72068
|
+
`TinaCMS: TinaCloud session check failed (status ${res.status}).`,
|
|
72069
|
+
(val == null ? void 0 : val.error) ?? val
|
|
72070
|
+
);
|
|
71439
72071
|
return null;
|
|
71440
72072
|
}
|
|
71441
72073
|
return val;
|
|
71442
72074
|
} catch (e) {
|
|
72075
|
+
if (e instanceof TypeError || isErrorNamed(e, "AbortError")) {
|
|
72076
|
+
throw e;
|
|
72077
|
+
}
|
|
71443
72078
|
console.error(e);
|
|
71444
72079
|
return null;
|
|
71445
72080
|
}
|
|
@@ -71556,6 +72191,8 @@ class Client {
|
|
|
71556
72191
|
// automatically hooked into global event bus when attached via cms.
|
|
71557
72192
|
__publicField(this, "protectedBranches", []);
|
|
71558
72193
|
__publicField(this, "usingEditorialWorkflow", false);
|
|
72194
|
+
// Whatever the auth provider returned from getUser().
|
|
72195
|
+
__publicField(this, "user");
|
|
71559
72196
|
__publicField(this, "addPendingContent", async (props) => {
|
|
71560
72197
|
const mutation = `#graphql
|
|
71561
72198
|
mutation addPendingDocumentMutation(
|
|
@@ -71655,13 +72292,24 @@ mutation addPendingDocumentMutation(
|
|
|
71655
72292
|
}
|
|
71656
72293
|
);
|
|
71657
72294
|
this.clientId = options.clientId;
|
|
71658
|
-
this.authProvider =
|
|
71659
|
-
|
|
71660
|
-
|
|
71661
|
-
|
|
71662
|
-
|
|
71663
|
-
|
|
71664
|
-
|
|
72295
|
+
this.authProvider = this.adoptAuthProvider(
|
|
72296
|
+
((_u = (_t = (_s = this.schema) == null ? void 0 : _s.config) == null ? void 0 : _t.config) == null ? void 0 : _u.authProvider) || new TinaCloudAuthProvider({
|
|
72297
|
+
clientId: options.clientId,
|
|
72298
|
+
identityApiUrl: this.identityApiUrl,
|
|
72299
|
+
getTokenFn: options.getTokenFn,
|
|
72300
|
+
tokenStorage,
|
|
72301
|
+
frontendUrl: this.frontendUrl
|
|
72302
|
+
})
|
|
72303
|
+
);
|
|
72304
|
+
}
|
|
72305
|
+
/**
|
|
72306
|
+
* Every provider swap must come through here: the listener is what turns a
|
|
72307
|
+
* REST 401 into the auth wall re-arming, and a bare field assignment would
|
|
72308
|
+
* silently drop it.
|
|
72309
|
+
*/
|
|
72310
|
+
adoptAuthProvider(provider) {
|
|
72311
|
+
provider.sessionExpiredListener = () => dispatchSessionExpired(this.events);
|
|
72312
|
+
return provider;
|
|
71665
72313
|
}
|
|
71666
72314
|
get isLocalMode() {
|
|
71667
72315
|
return false;
|
|
@@ -71706,6 +72354,17 @@ mutation addPendingDocumentMutation(
|
|
|
71706
72354
|
variables
|
|
71707
72355
|
})
|
|
71708
72356
|
});
|
|
72357
|
+
if (res.status === 401) {
|
|
72358
|
+
res.json().catch(() => {
|
|
72359
|
+
});
|
|
72360
|
+
if (this.isCustomContentApi) {
|
|
72361
|
+
console.error(
|
|
72362
|
+
`TinaCMS: the content API at ${this.contentApiUrl} returned 401. If signing in again does not resolve this, check the backend's auth configuration (clientId: ${this.options.clientId}, branch: ${this.branch}).`
|
|
72363
|
+
);
|
|
72364
|
+
}
|
|
72365
|
+
dispatchSessionExpired(this.events);
|
|
72366
|
+
throw new SessionExpiredError();
|
|
72367
|
+
}
|
|
71709
72368
|
if (res.status !== 200) {
|
|
71710
72369
|
let errorMessage = `Unable to complete request, ${res.statusText}`;
|
|
71711
72370
|
const resBody = await res.json();
|
|
@@ -72127,6 +72786,10 @@ mutation addPendingDocumentMutation(
|
|
|
72127
72786
|
throw error;
|
|
72128
72787
|
}
|
|
72129
72788
|
}
|
|
72789
|
+
/**
|
|
72790
|
+
* The server normalises `branchName`, so follow-up calls must use the
|
|
72791
|
+
* `branchName` from the response rather than the one they sent.
|
|
72792
|
+
*/
|
|
72130
72793
|
async startMediaEditorialWorkflow(options) {
|
|
72131
72794
|
const url = `${this.contentApiBase}/editorial-workflow/${this.clientId}/media`;
|
|
72132
72795
|
return await this.postEditorialWorkflow(
|
|
@@ -72151,7 +72814,9 @@ class LocalClient extends Client {
|
|
|
72151
72814
|
customContentApiUrl: props && props.customContentApiUrl ? props.customContentApiUrl : DEFAULT_LOCAL_TINA_GQL_SERVER_URL
|
|
72152
72815
|
};
|
|
72153
72816
|
super(clientProps);
|
|
72154
|
-
this.authProvider =
|
|
72817
|
+
this.authProvider = this.adoptAuthProvider(
|
|
72818
|
+
((_c = (_b = (_a = this.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.config) == null ? void 0 : _c.authProvider) || new LocalAuthProvider()
|
|
72819
|
+
);
|
|
72155
72820
|
}
|
|
72156
72821
|
get isLocalMode() {
|
|
72157
72822
|
return true;
|
|
@@ -72396,6 +73061,7 @@ const useTinaAuthRedirect = (params, enabled = true) => {
|
|
|
72396
73061
|
function sleep(ms) {
|
|
72397
73062
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
72398
73063
|
}
|
|
73064
|
+
const SESSION_EXPIRED_MESSAGE = "Your session has ended. Please sign in again to continue editing.";
|
|
72399
73065
|
const AuthWallInner = ({
|
|
72400
73066
|
children,
|
|
72401
73067
|
cms,
|
|
@@ -72417,6 +73083,15 @@ const AuthWallInner = ({
|
|
|
72417
73083
|
const [showChildren, setShowChildren] = useState(false);
|
|
72418
73084
|
const [authProps, setAuthProps] = useState({ username: "", password: "" });
|
|
72419
73085
|
const [authenticated, setAuthenticated] = useState(false);
|
|
73086
|
+
const [sessionExpired, setSessionExpired] = useState(false);
|
|
73087
|
+
React__default.useEffect(
|
|
73088
|
+
() => cms.events.subscribe("cms:session-expired", () => {
|
|
73089
|
+
setSessionExpired(true);
|
|
73090
|
+
setShowChildren(false);
|
|
73091
|
+
setActiveModal("authenticate");
|
|
73092
|
+
}),
|
|
73093
|
+
[]
|
|
73094
|
+
);
|
|
72420
73095
|
React__default.useEffect(() => {
|
|
72421
73096
|
let mounted = true;
|
|
72422
73097
|
if (isAuthRedirect) {
|
|
@@ -72432,6 +73107,7 @@ const AuthWallInner = ({
|
|
|
72432
73107
|
if (!mounted) return;
|
|
72433
73108
|
if (isAuthorized) {
|
|
72434
73109
|
const user = await client.authProvider.getUser();
|
|
73110
|
+
client.user = user;
|
|
72435
73111
|
if (user.passwordChangeRequired) {
|
|
72436
73112
|
window.location.hash = "#/screens/change_password";
|
|
72437
73113
|
}
|
|
@@ -72467,6 +73143,7 @@ const AuthWallInner = ({
|
|
|
72467
73143
|
}, [authenticated]);
|
|
72468
73144
|
const onAuthenticated = async () => {
|
|
72469
73145
|
setAuthenticated(true);
|
|
73146
|
+
setSessionExpired(false);
|
|
72470
73147
|
setActiveModal(null);
|
|
72471
73148
|
cms.events.dispatch({ type: "cms:login" });
|
|
72472
73149
|
};
|
|
@@ -72486,7 +73163,7 @@ const AuthWallInner = ({
|
|
|
72486
73163
|
}
|
|
72487
73164
|
return onAuthenticated();
|
|
72488
73165
|
} catch (e) {
|
|
72489
|
-
if (e instanceof AuthenticationCancelledError || (e
|
|
73166
|
+
if (e instanceof AuthenticationCancelledError || isErrorNamed(e, "AuthenticationCancelledError")) {
|
|
72490
73167
|
return;
|
|
72491
73168
|
}
|
|
72492
73169
|
console.error(e);
|
|
@@ -72513,6 +73190,7 @@ const AuthWallInner = ({
|
|
|
72513
73190
|
ModalBuilder,
|
|
72514
73191
|
{
|
|
72515
73192
|
title: modalTitle,
|
|
73193
|
+
error: sessionExpired ? SESSION_EXPIRED_MESSAGE : void 0,
|
|
72516
73194
|
message: isTinaCloud ? /* @__PURE__ */ React__default.createElement(
|
|
72517
73195
|
"img",
|
|
72518
73196
|
{
|
|
@@ -72538,6 +73216,7 @@ const AuthWallInner = ({
|
|
|
72538
73216
|
ModalBuilder,
|
|
72539
73217
|
{
|
|
72540
73218
|
title: modalTitle,
|
|
73219
|
+
error: sessionExpired ? SESSION_EXPIRED_MESSAGE : void 0,
|
|
72541
73220
|
message: "",
|
|
72542
73221
|
close,
|
|
72543
73222
|
busy: isAuthRedirect,
|
|
@@ -72759,9 +73438,14 @@ const TinaCloudProvider = (props) => {
|
|
|
72759
73438
|
}
|
|
72760
73439
|
}, []);
|
|
72761
73440
|
React__default.useEffect(() => {
|
|
72762
|
-
const setupEditorialWorkflow = () => {
|
|
72763
|
-
|
|
72764
|
-
|
|
73441
|
+
const setupEditorialWorkflow = async () => {
|
|
73442
|
+
var _a2;
|
|
73443
|
+
try {
|
|
73444
|
+
const token = await client.authProvider.getToken();
|
|
73445
|
+
if (!(token == null ? void 0 : token.access_token) && !(token == null ? void 0 : token.id_token)) {
|
|
73446
|
+
return;
|
|
73447
|
+
}
|
|
73448
|
+
const project = await client.getProject();
|
|
72765
73449
|
if ((_a2 = project == null ? void 0 : project.features) == null ? void 0 : _a2.includes("editorial-workflow")) {
|
|
72766
73450
|
cms.flags.set("branch-switcher", true);
|
|
72767
73451
|
client.usingEditorialWorkflow = true;
|
|
@@ -72770,7 +73454,9 @@ const TinaCloudProvider = (props) => {
|
|
|
72770
73454
|
setCurrentBranch(project.defaultBranch || "main");
|
|
72771
73455
|
}
|
|
72772
73456
|
}
|
|
72773
|
-
})
|
|
73457
|
+
} catch (e) {
|
|
73458
|
+
console.error("TinaCMS: unable to load project settings", e);
|
|
73459
|
+
}
|
|
72774
73460
|
};
|
|
72775
73461
|
if (isTinaCloud) {
|
|
72776
73462
|
setupEditorialWorkflow();
|
|
@@ -73826,6 +74512,7 @@ const CollectionListPage = () => {
|
|
|
73826
74512
|
);
|
|
73827
74513
|
return (_b2 = (_a2 = doc == null ? void 0 : doc.document) == null ? void 0 : _a2._sys) == null ? void 0 : _b2.hasReferences;
|
|
73828
74514
|
} catch (error) {
|
|
74515
|
+
if (isSessionExpiredError(error)) throw error;
|
|
73829
74516
|
cms.alerts.error(
|
|
73830
74517
|
"Document was not found, ask a developer for help or check the console for an error message"
|
|
73831
74518
|
);
|
|
@@ -73841,6 +74528,7 @@ const CollectionListPage = () => {
|
|
|
73841
74528
|
);
|
|
73842
74529
|
reFetchCollection();
|
|
73843
74530
|
} catch (error) {
|
|
74531
|
+
if (isSessionExpiredError(error)) throw error;
|
|
73844
74532
|
if (error.message.includes(ERR_HAS_REFERENCES)) {
|
|
73845
74533
|
cms.alerts.error(
|
|
73846
74534
|
error.message.split("\n ").filter(Boolean)[1]
|
|
@@ -73870,6 +74558,7 @@ const CollectionListPage = () => {
|
|
|
73870
74558
|
);
|
|
73871
74559
|
reFetchCollection();
|
|
73872
74560
|
} catch (error) {
|
|
74561
|
+
if (isSessionExpiredError(error)) throw error;
|
|
73873
74562
|
cms.alerts.warn(
|
|
73874
74563
|
"Document was not deleted, ask a developer for help or check the console for an error message"
|
|
73875
74564
|
);
|
|
@@ -73902,6 +74591,7 @@ const CollectionListPage = () => {
|
|
|
73902
74591
|
);
|
|
73903
74592
|
reFetchCollection();
|
|
73904
74593
|
} catch (error) {
|
|
74594
|
+
if (isSessionExpiredError(error)) throw error;
|
|
73905
74595
|
if (error.message && error.message.includes(ERR_ALREADY_EXISTS)) {
|
|
73906
74596
|
cms.alerts.error(
|
|
73907
74597
|
`Document was not renamed. The filename "${vars.newRelativePath}" is already used by another document, please choose a different name.`
|
|
@@ -73948,6 +74638,7 @@ const CollectionListPage = () => {
|
|
|
73948
74638
|
);
|
|
73949
74639
|
cms.alerts.info("Folder was successfully created");
|
|
73950
74640
|
} catch (error) {
|
|
74641
|
+
if (isSessionExpiredError(error)) throw error;
|
|
73951
74642
|
if (error.message && error.message.includes(ERR_ALREADY_EXISTS)) {
|
|
73952
74643
|
cms.alerts.error(
|
|
73953
74644
|
`Folder was not created, folder with name "${vars.folderName}" already exists ${folder.name ? `in ${folder.name}` : ""}`
|
|
@@ -74511,6 +75202,7 @@ const DeleteModal = ({
|
|
|
74511
75202
|
useEffect(() => {
|
|
74512
75203
|
checkRefsFunc().then((result) => {
|
|
74513
75204
|
setHasRefs(result);
|
|
75205
|
+
}).catch(() => {
|
|
74514
75206
|
});
|
|
74515
75207
|
}, [filename, checkRefsFunc]);
|
|
74516
75208
|
return /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, { close: close2 }, "Delete ", filename), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("p", null, `Are you sure you want to delete ${filename}?${hasRefs ? " References to this document will also be deleted." : ""}`)), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement(Button$2, { style: { flexGrow: 2 }, onClick: close2 }, "Cancel"), /* @__PURE__ */ React__default.createElement(
|
|
@@ -74519,7 +75211,10 @@ const DeleteModal = ({
|
|
|
74519
75211
|
style: { flexGrow: 3 },
|
|
74520
75212
|
variant: "danger",
|
|
74521
75213
|
onClick: async () => {
|
|
74522
|
-
|
|
75214
|
+
try {
|
|
75215
|
+
await deleteFunc();
|
|
75216
|
+
} catch {
|
|
75217
|
+
}
|
|
74523
75218
|
close2();
|
|
74524
75219
|
}
|
|
74525
75220
|
},
|
|
@@ -74657,6 +75352,18 @@ const shouldAutoOpenCollectionDocument = ({
|
|
|
74657
75352
|
((_b = (_a = collection.documents) == null ? void 0 : _a.edges) == null ? void 0 : _b.length) === 1 && // Check to make sure the file is not a folder
|
|
74658
75353
|
((_e = (_d = (_c = collection.documents) == null ? void 0 : _c.edges[0]) == null ? void 0 : _d.node) == null ? void 0 : _e.__typename) !== "Folder";
|
|
74659
75354
|
};
|
|
75355
|
+
const UnableToLoadModal = ({ message }) => /* @__PURE__ */ React__default.createElement(Modal, null, /* @__PURE__ */ React__default.createElement(PopupModal, null, /* @__PURE__ */ React__default.createElement(ModalHeader, null, "Unable to load"), /* @__PURE__ */ React__default.createElement(ModalBody, { padded: true }, /* @__PURE__ */ React__default.createElement("div", { className: "tina-prose" }, message)), /* @__PURE__ */ React__default.createElement(ModalActions, null, /* @__PURE__ */ React__default.createElement("div", { className: "flex-1" }), /* @__PURE__ */ React__default.createElement(
|
|
75356
|
+
Button$2,
|
|
75357
|
+
{
|
|
75358
|
+
style: { flexGrow: 1 },
|
|
75359
|
+
className: "w-full",
|
|
75360
|
+
variant: "primary",
|
|
75361
|
+
onClick: () => {
|
|
75362
|
+
window.location.reload();
|
|
75363
|
+
}
|
|
75364
|
+
},
|
|
75365
|
+
"Reload"
|
|
75366
|
+
))));
|
|
74660
75367
|
const isValidSortKey = (sortKey, collection) => {
|
|
74661
75368
|
if (collection.fields) {
|
|
74662
75369
|
const sortKeys = collection.fields.map((x) => x.name);
|
|
@@ -74697,10 +75404,13 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, folder,
|
|
|
74697
75404
|
useEffect(() => {
|
|
74698
75405
|
let cancelled = false;
|
|
74699
75406
|
const fetchCollection = async () => {
|
|
74700
|
-
if (
|
|
74701
|
-
|
|
74702
|
-
|
|
74703
|
-
|
|
75407
|
+
if (folder.loading) {
|
|
75408
|
+
return;
|
|
75409
|
+
}
|
|
75410
|
+
try {
|
|
75411
|
+
if (await api.isAuthenticated() && !cancelled) {
|
|
75412
|
+
const { name: name2, order } = JSON.parse(sortKey || "{}");
|
|
75413
|
+
const validSortKey = isValidSortKey(name2, collectionExtra) ? name2 : void 0;
|
|
74704
75414
|
const collection2 = await api.fetchCollection(
|
|
74705
75415
|
collectionName,
|
|
74706
75416
|
includeDocuments,
|
|
@@ -74711,14 +75421,21 @@ const useGetCollection = (cms, collectionName, includeDocuments = true, folder,
|
|
|
74711
75421
|
filterArgs
|
|
74712
75422
|
);
|
|
74713
75423
|
setCollection(collection2);
|
|
74714
|
-
}
|
|
75424
|
+
} else if (!cancelled) {
|
|
75425
|
+
dispatchSessionExpired(cms.events);
|
|
75426
|
+
setCollection(void 0);
|
|
75427
|
+
}
|
|
75428
|
+
} catch (error2) {
|
|
75429
|
+
setCollection(void 0);
|
|
75430
|
+
if (!isSessionExpiredError(error2)) {
|
|
74715
75431
|
cms.alerts.error(
|
|
74716
75432
|
`[${error2.name}] GetCollection failed: ${error2.message}`
|
|
74717
75433
|
);
|
|
74718
75434
|
console.error(error2);
|
|
74719
|
-
setCollection(void 0);
|
|
74720
75435
|
setError(error2);
|
|
74721
75436
|
}
|
|
75437
|
+
}
|
|
75438
|
+
if (!cancelled) {
|
|
74722
75439
|
setLoading(false);
|
|
74723
75440
|
}
|
|
74724
75441
|
};
|
|
@@ -74751,8 +75468,11 @@ const useSearchCollection = (cms, collectionName, includeDocuments = true, folde
|
|
|
74751
75468
|
useEffect(() => {
|
|
74752
75469
|
let cancelled = false;
|
|
74753
75470
|
const searchCollection = async () => {
|
|
74754
|
-
if (
|
|
74755
|
-
|
|
75471
|
+
if (folder.loading) {
|
|
75472
|
+
return;
|
|
75473
|
+
}
|
|
75474
|
+
try {
|
|
75475
|
+
if (await api.isAuthenticated() && !cancelled) {
|
|
74756
75476
|
const response = await cms.api.search.query(search, {
|
|
74757
75477
|
limit: 15,
|
|
74758
75478
|
cursor: after,
|
|
@@ -74765,6 +75485,15 @@ const useSearchCollection = (cms, collectionName, includeDocuments = true, folde
|
|
|
74765
75485
|
return api.fetchDocument(collection2, relativePath, false);
|
|
74766
75486
|
})
|
|
74767
75487
|
);
|
|
75488
|
+
if (docs.some(
|
|
75489
|
+
(p) => p.status === "rejected" && isSessionExpiredError(p.reason)
|
|
75490
|
+
)) {
|
|
75491
|
+
setCollection(void 0);
|
|
75492
|
+
if (!cancelled) {
|
|
75493
|
+
setLoading(false);
|
|
75494
|
+
}
|
|
75495
|
+
return;
|
|
75496
|
+
}
|
|
74768
75497
|
const edges = docs.filter((p) => {
|
|
74769
75498
|
var _a;
|
|
74770
75499
|
return p.status === "fulfilled" && !!((_a = p.value) == null ? void 0 : _a.document);
|
|
@@ -74786,14 +75515,21 @@ const useSearchCollection = (cms, collectionName, includeDocuments = true, folde
|
|
|
74786
75515
|
}
|
|
74787
75516
|
};
|
|
74788
75517
|
setCollection(collectionData);
|
|
74789
|
-
}
|
|
75518
|
+
} else if (!cancelled) {
|
|
75519
|
+
dispatchSessionExpired(cms.events);
|
|
75520
|
+
setCollection(void 0);
|
|
75521
|
+
}
|
|
75522
|
+
} catch (error2) {
|
|
75523
|
+
setCollection(void 0);
|
|
75524
|
+
if (!isSessionExpiredError(error2)) {
|
|
74790
75525
|
cms.alerts.error(
|
|
74791
75526
|
`[${error2.name}] GetCollection failed: ${error2.message}`
|
|
74792
75527
|
);
|
|
74793
75528
|
console.error(error2);
|
|
74794
|
-
setCollection(void 0);
|
|
74795
75529
|
setError(error2);
|
|
74796
75530
|
}
|
|
75531
|
+
}
|
|
75532
|
+
if (!cancelled) {
|
|
74797
75533
|
setLoading(false);
|
|
74798
75534
|
}
|
|
74799
75535
|
};
|
|
@@ -74851,7 +75587,7 @@ const GetCollection = ({
|
|
|
74851
75587
|
);
|
|
74852
75588
|
useEffect(() => {
|
|
74853
75589
|
var _a, _b, _c, _d;
|
|
74854
|
-
if (loading) return;
|
|
75590
|
+
if (loading || !collection) return;
|
|
74855
75591
|
const collectionDefinition = cms.api.tina.schema.getCollection(
|
|
74856
75592
|
collection.name
|
|
74857
75593
|
);
|
|
@@ -74880,6 +75616,9 @@ const GetCollection = ({
|
|
|
74880
75616
|
if (loading) {
|
|
74881
75617
|
return /* @__PURE__ */ React__default.createElement(LoadingPage, null);
|
|
74882
75618
|
}
|
|
75619
|
+
if (!collection) {
|
|
75620
|
+
return /* @__PURE__ */ React__default.createElement(UnableToLoadModal, { message: "This collection could not be loaded." });
|
|
75621
|
+
}
|
|
74883
75622
|
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(collection, loading, reFetchCollection, collectionExtra));
|
|
74884
75623
|
};
|
|
74885
75624
|
const createDocument = async (cms, collection, template, mutationInfo, folder, values) => {
|
|
@@ -74898,9 +75637,7 @@ const createDocument = async (cms, collection, template, mutationInfo, folder, v
|
|
|
74898
75637
|
if (await api.isAuthenticated()) {
|
|
74899
75638
|
await api.createDocument(collection, relativePath, params);
|
|
74900
75639
|
} else {
|
|
74901
|
-
|
|
74902
|
-
cms.alerts.error(authMessage);
|
|
74903
|
-
console.error(authMessage);
|
|
75640
|
+
dispatchSessionExpired(cms.events);
|
|
74904
75641
|
return false;
|
|
74905
75642
|
}
|
|
74906
75643
|
};
|
|
@@ -75083,7 +75820,7 @@ const RenderForm$1 = ({
|
|
|
75083
75820
|
onSubmit: async (values) => {
|
|
75084
75821
|
try {
|
|
75085
75822
|
const folderName2 = folder.fullyQualifiedName ? folder.name : "";
|
|
75086
|
-
await createDocument(
|
|
75823
|
+
const result = await createDocument(
|
|
75087
75824
|
cms,
|
|
75088
75825
|
collection,
|
|
75089
75826
|
template,
|
|
@@ -75091,6 +75828,7 @@ const RenderForm$1 = ({
|
|
|
75091
75828
|
folderName2,
|
|
75092
75829
|
values
|
|
75093
75830
|
);
|
|
75831
|
+
if (result === false) return;
|
|
75094
75832
|
cms.alerts.success("Document created!");
|
|
75095
75833
|
setTimeout(() => {
|
|
75096
75834
|
navigate(
|
|
@@ -75098,6 +75836,7 @@ const RenderForm$1 = ({
|
|
|
75098
75836
|
);
|
|
75099
75837
|
}, 10);
|
|
75100
75838
|
} catch (error) {
|
|
75839
|
+
if (isSessionExpiredError(error)) throw error;
|
|
75101
75840
|
const defaultErrorText = "There was a problem saving your document.";
|
|
75102
75841
|
if (error.message && error.message.includes(ERR_ALREADY_EXISTS)) {
|
|
75103
75842
|
cms.alerts.error(
|
|
@@ -75160,8 +75899,8 @@ const useGetDocument = (cms, collectionName, relativePath) => {
|
|
|
75160
75899
|
useEffect(() => {
|
|
75161
75900
|
let isCancelled = false;
|
|
75162
75901
|
const fetchDocument = async () => {
|
|
75163
|
-
|
|
75164
|
-
|
|
75902
|
+
try {
|
|
75903
|
+
if (await api.isAuthenticated() && !isCancelled) {
|
|
75165
75904
|
const response = await api.fetchDocument(
|
|
75166
75905
|
collectionName,
|
|
75167
75906
|
relativePath
|
|
@@ -75169,19 +75908,24 @@ const useGetDocument = (cms, collectionName, relativePath) => {
|
|
|
75169
75908
|
if (!isCancelled) {
|
|
75170
75909
|
setDocument(response.document);
|
|
75171
75910
|
}
|
|
75172
|
-
}
|
|
75173
|
-
|
|
75911
|
+
} else if (!isCancelled) {
|
|
75912
|
+
dispatchSessionExpired(cms.events);
|
|
75913
|
+
setDocument(void 0);
|
|
75914
|
+
}
|
|
75915
|
+
} catch (error2) {
|
|
75916
|
+
if (!isCancelled) {
|
|
75917
|
+
setDocument(void 0);
|
|
75918
|
+
if (!isSessionExpiredError(error2)) {
|
|
75174
75919
|
cms.alerts.error(
|
|
75175
75920
|
`[${error2.name}] GetDocument failed: ${error2.message}`
|
|
75176
75921
|
);
|
|
75177
75922
|
console.error(error2);
|
|
75178
|
-
setDocument(void 0);
|
|
75179
75923
|
setError(error2);
|
|
75180
75924
|
}
|
|
75181
75925
|
}
|
|
75182
|
-
|
|
75183
|
-
|
|
75184
|
-
|
|
75926
|
+
}
|
|
75927
|
+
if (!isCancelled) {
|
|
75928
|
+
setLoading(false);
|
|
75185
75929
|
}
|
|
75186
75930
|
};
|
|
75187
75931
|
setLoading(true);
|
|
@@ -75209,6 +75953,9 @@ const GetDocument = ({
|
|
|
75209
75953
|
if (loading) {
|
|
75210
75954
|
return /* @__PURE__ */ React__default.createElement(LoadingPage, null);
|
|
75211
75955
|
}
|
|
75956
|
+
if (!document2) {
|
|
75957
|
+
return /* @__PURE__ */ React__default.createElement(UnableToLoadModal, { message: "This document could not be loaded." });
|
|
75958
|
+
}
|
|
75212
75959
|
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, children(document2, loading));
|
|
75213
75960
|
};
|
|
75214
75961
|
const CollectionDuplicatePage = () => {
|
|
@@ -75260,9 +76007,7 @@ const updateDocument = async (cms, relativePath, collection, mutationInfo, value
|
|
|
75260
76007
|
if (await api.isAuthenticated()) {
|
|
75261
76008
|
await api.updateDocument(collection, relativePath, params);
|
|
75262
76009
|
} else {
|
|
75263
|
-
|
|
75264
|
-
cms.alerts.error(authMessage);
|
|
75265
|
-
console.error(authMessage);
|
|
76010
|
+
dispatchSessionExpired(cms.events);
|
|
75266
76011
|
return false;
|
|
75267
76012
|
}
|
|
75268
76013
|
};
|
|
@@ -75340,15 +76085,17 @@ const RenderForm = ({
|
|
|
75340
76085
|
initialValues: document2._values,
|
|
75341
76086
|
onSubmit: async (values) => {
|
|
75342
76087
|
try {
|
|
75343
|
-
await updateDocument(
|
|
76088
|
+
const result = await updateDocument(
|
|
75344
76089
|
cms,
|
|
75345
76090
|
relativePath,
|
|
75346
76091
|
collection,
|
|
75347
76092
|
mutationInfo,
|
|
75348
76093
|
values
|
|
75349
76094
|
);
|
|
76095
|
+
if (result === false) return;
|
|
75350
76096
|
cms.alerts.success("Document updated!");
|
|
75351
76097
|
} catch (error) {
|
|
76098
|
+
if (isSessionExpiredError(error)) throw error;
|
|
75352
76099
|
cms.alerts.error(
|
|
75353
76100
|
() => ErrorDialog({
|
|
75354
76101
|
title: "There was a problem saving your document",
|
|
@@ -75558,6 +76305,9 @@ const CheckSchema = ({
|
|
|
75558
76305
|
);
|
|
75559
76306
|
}
|
|
75560
76307
|
}).catch((error) => {
|
|
76308
|
+
if (isSessionExpiredError(error)) {
|
|
76309
|
+
return;
|
|
76310
|
+
}
|
|
75561
76311
|
if (error.message.includes(ERR_NOT_INDEXED)) {
|
|
75562
76312
|
setSchemaMissingError(true);
|
|
75563
76313
|
} else {
|
|
@@ -75871,6 +76621,7 @@ export {
|
|
|
75871
76621
|
BlocksFieldPlugin,
|
|
75872
76622
|
BoldIcon$1 as BoldIcon,
|
|
75873
76623
|
BranchButton,
|
|
76624
|
+
BranchCreator,
|
|
75874
76625
|
BranchDataProvider,
|
|
75875
76626
|
BranchItem,
|
|
75876
76627
|
BranchPreviewButton,
|
|
@@ -76021,6 +76772,7 @@ export {
|
|
|
76021
76772
|
Select$1 as Select,
|
|
76022
76773
|
SelectField,
|
|
76023
76774
|
SelectFieldPlugin,
|
|
76775
|
+
SessionExpiredError,
|
|
76024
76776
|
SettingsIcon,
|
|
76025
76777
|
StrikethroughIcon,
|
|
76026
76778
|
StyledFile,
|
|
@@ -76073,6 +76825,7 @@ export {
|
|
|
76073
76825
|
get,
|
|
76074
76826
|
getFilteredBranchList,
|
|
76075
76827
|
getStaticPropsForTina,
|
|
76828
|
+
isSessionExpiredError,
|
|
76076
76829
|
passwordFieldClasses,
|
|
76077
76830
|
resolveField,
|
|
76078
76831
|
safeAssertShape,
|