@firecms/core
Version:
Awesome Firebase/Firestore-based headless open-source CMS
1,459 lines • 1.63 MB
JavaScript
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
import { c } from "react-compiler-runtime";
import * as React from "react";
import React__default, { useState, useRef, useEffect, useContext, useCallback, useMemo, createElement, createRef, createContext, forwardRef, memo, useLayoutEffect } from "react";
import { getColorSchemeForSeed, CHIP_COLORS, FunctionsIcon, CircleIcon, iconKeys, coolIconKeys, Icon, Tooltip, ErrorIcon, Typography, IconButton, ContentCopyIcon, OpenInNewIcon, DescriptionIcon, cls, Skeleton, Chip, defaultBorderMixin, KeyboardTabIcon, Checkbox, AccountCircleIcon, Markdown, TextareaAutosize, focusedDisabled, MultiSelect, MultiSelectItem, Select, SelectItem, BooleanSwitch, DateTimeField, paperMixin, EditIcon, DoNotDisturbOnIcon, Menu, MenuItem, MoreVertIcon, Badge, SearchBar, CircularProgress, ArrowUpwardIcon, Popover, FilterListIcon, Button, CenteredView, AssignmentIcon, Label, CloseIcon, TextField, BooleanSwitchWithLabel, useOutsideAlerter, Dialog, DialogTitle, DialogContent, DialogActions, FileCopyIcon, DeleteIcon, AddIcon, StarIcon, Collapse, ExpandablePanel, ArrowForwardIcon, Card, cardMixin, cardClickableMixin, Container, getColorSchemeForKey, RefreshIcon, ListIcon, AppsIcon, ViewKanbanIcon, ToggleButtonGroup, ViewColumnIcon, LoadingButton, WarningIcon, KeyboardArrowDownIcon, VisibilityIcon, CheckIcon, CancelIcon, Alert, NotesIcon, InfoIcon, fieldBackgroundMixin, RemoveIcon, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, ArrowDropDownIcon, TextFieldsIcon, CheckBoxIcon, LooksOneIcon, LooksTwoIcon, Looks3Icon, FormatListBulletedIcon, FormatListNumberedIcon, FormatQuoteIcon, CodeIcon, ImageIcon, TableChartIcon, AutoFixHighIcon, FormatBoldIcon, FormatItalicIcon, FormatUnderlinedIcon, FormatStrikethroughIcon, useInjectStyles, Separator, FilterListOffIcon, SearchIcon, DarkModeIcon, LightModeIcon, BrightnessMediumIcon, LogoutIcon, Avatar, HandleIcon, KeyboardArrowUpIcon, debounce, AutoAwesomeIcon, TranslateIcon, OpenInFullIcon, Sheet, Tab, Tabs, ExpandMoreIcon, ViewStreamIcon, RepeatIcon, BallotIcon, ScheduleIcon, AddLinkIcon, LinkIcon, DriveFolderUploadIcon, UploadFileIcon, NumbersIcon, PersonIcon, ListAltIcon, FlagIcon, MailIcon, HttpIcon, SubjectIcon, ShortTextIcon, MenuIcon, ChevronLeftIcon } from "@firecms/ui";
import { SnackbarProvider as SnackbarProvider$1, useSnackbar } from "notistack";
import hash from "object-hash";
import { getIn, setIn, useFormex, useCreateFormex, Formex, Field } from "@firecms/formex";
import { useLocation, useNavigate, Link, NavLink, Routes, Route, createBrowserRouter, RouterProvider } from "react-router-dom";
import Fuse from "fuse.js";
import equal from "react-fast-compare";
import jsonLogic from "json-logic-js";
import { useTranslation as useTranslation$1, initReactI18next, I18nextProvider } from "react-i18next";
import { format } from "date-fns";
import * as locales from "date-fns/locale";
import useMeasure from "react-use-measure";
import * as yup from "yup";
import { FixedSizeList } from "react-window";
import { useSensors, useSensor, PointerSensor, DndContext, closestCenter, MouseSensor, TouchSensor, KeyboardSensor, pointerWithin, closestCorners, getFirstCollision, rectIntersection, useDroppable, useDndMonitor, MeasuringStrategy, DragOverlay } from "@dnd-kit/core";
import { useSortable, arrayMove as arrayMove$1, SortableContext, horizontalListSortingStrategy, defaultAnimateLayoutChanges, rectSortingStrategy, verticalListSortingStrategy, sortableKeyboardCoordinates } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { restrictToVerticalAxis, restrictToWindowEdges } from "@dnd-kit/modifiers";
import { useDropzone } from "react-dropzone";
import Compressor from "compressorjs";
import i18next from "i18next";
import { autoUpdate, computePosition, offset, flip, shift } from "@floating-ui/dom";
import { NodeSelection, Plugin, PluginKey, TextSelection, EditorState } from "prosemirror-state";
import { Slot } from "@radix-ui/react-slot";
import { Schema, Fragment as Fragment$1, DOMParser, DOMSerializer } from "prosemirror-model";
import { setBlockType, wrapIn, toggleMark, baseKeymap } from "prosemirror-commands";
import { wrapInList, sinkListItem, liftListItem, splitListItem } from "prosemirror-schema-list";
import { tableNodes, addRowBefore, addRowAfter, deleteRow, addColumnBefore, addColumnAfter, deleteColumn, deleteTable, goToNextCell, columnResizing, tableEditing } from "prosemirror-tables";
import { DecorationSet, Decoration, EditorView } from "prosemirror-view";
import { MarkdownParser, MarkdownSerializer, defaultMarkdownParser, defaultMarkdownSerializer } from "prosemirror-markdown";
import markdownIt from "markdown-it";
import markdownItTaskLists from "markdown-it-task-lists";
import markdownItMark from "markdown-it-mark";
import markdownItIns from "markdown-it-ins";
import { keymap } from "prosemirror-keymap";
import { history, redo, undo } from "prosemirror-history";
import { dropPoint } from "prosemirror-transform";
import { gapCursor } from "prosemirror-gapcursor";
import { inputRules, smartQuotes, ellipsis, emDash, InputRule, wrappingInputRule, textblockTypeInputRule } from "prosemirror-inputrules";
import { createRoot } from "react-dom/client";
import { themes, Highlight } from "prism-react-renderer";
import { useLocation as useLocation$1, useBlocker } from "react-router";
import * as Portal from "@radix-ui/react-portal";
const SnackbarProvider = (t0) => {
const $ = c(2);
const {
children
} = t0;
let t1;
if ($[0] !== children) {
t1 = /* @__PURE__ */ jsx(SnackbarProvider$1, { maxSnack: 3, autoHideDuration: 3500, children });
$[0] = children;
$[1] = t1;
} else {
t1 = $[1];
}
return t1;
};
const DEFAULT_MODE_STATE = {
mode: "light",
setMode: (mode) => {
}
};
const ModeControllerContext = React__default.createContext(DEFAULT_MODE_STATE);
const ModeControllerProvider = ModeControllerContext.Provider;
const AuthControllerContext = React__default.createContext({});
const DataSourceContext = React__default.createContext({});
const NavigationContext = React__default.createContext({});
const CustomizationControllerContext = React__default.createContext({});
const SideEntityControllerContext = React__default.createContext({});
const SideDialogsControllerContext = React__default.createContext({});
const AnalyticsContext = React__default.createContext({});
const StorageSourceContext = React__default.createContext({});
const UserConfigurationPersistenceContext = React__default.createContext(void 0);
const DialogsControllerContext = React__default.createContext({});
const DialogsProvider = (t0) => {
const $ = c(16);
const {
children
} = t0;
let t1;
if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
t1 = [];
$[0] = t1;
} else {
t1 = $[0];
}
const [dialogEntries, setDialogEntries] = useState(t1);
const dialogEntriesRef = useRef(dialogEntries);
let t2;
if ($[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
t2 = (newPanels) => {
dialogEntriesRef.current = newPanels;
setDialogEntries(newPanels);
};
$[1] = t2;
} else {
t2 = $[1];
}
const updateDialogEntries = t2;
let t3;
if ($[2] !== dialogEntries.length) {
t3 = () => {
if (dialogEntries.length === 0) {
return;
}
const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];
updateDialogEntries(updatedPanels);
};
$[2] = dialogEntries.length;
$[3] = t3;
} else {
t3 = $[3];
}
const close = t3;
let t4;
if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
t4 = (dialogEntry) => {
const updatedPanels_0 = [...dialogEntriesRef.current, dialogEntry];
updateDialogEntries(updatedPanels_0);
return {
closeDialog: () => {
const updatedPanels_1 = dialogEntriesRef.current.filter((e) => e.key !== dialogEntry.key);
updateDialogEntries(updatedPanels_1);
}
};
};
$[4] = t4;
} else {
t4 = $[4];
}
const open = t4;
let t5;
if ($[5] !== close) {
t5 = {
open,
close
};
$[5] = close;
$[6] = t5;
} else {
t5 = $[6];
}
let t6;
if ($[7] !== close || $[8] !== dialogEntries) {
let t72;
if ($[10] !== close) {
t72 = (entry, i) => /* @__PURE__ */ jsx(entry.Component, { open: true, closeDialog: close, ...entry.props }, `dialog_${i}`);
$[10] = close;
$[11] = t72;
} else {
t72 = $[11];
}
t6 = dialogEntries.map(t72);
$[7] = close;
$[8] = dialogEntries;
$[9] = t6;
} else {
t6 = $[9];
}
let t7;
if ($[12] !== children || $[13] !== t5 || $[14] !== t6) {
t7 = /* @__PURE__ */ jsxs(DialogsControllerContext.Provider, { value: t5, children: [
children,
t6
] });
$[12] = children;
$[13] = t5;
$[14] = t6;
$[15] = t7;
} else {
t7 = $[15];
}
return t7;
};
const InternalUserManagementContext = React__default.createContext({});
function removeInitialAndTrailingSlashes(s) {
return removeInitialSlash(removeTrailingSlash(s));
}
function removeInitialSlash(s) {
if (s.startsWith("/")) return s.slice(1);
else return s;
}
function removeTrailingSlash(s) {
if (s.endsWith("/")) return s.slice(0, -1);
else return s;
}
function addInitialSlash(s) {
if (s.startsWith("/")) return s;
else return `/${s}`;
}
function getLastSegment(path) {
const cleanPath = removeInitialAndTrailingSlashes(path);
if (cleanPath.includes("/")) {
const segments = cleanPath.split("/");
return segments[segments.length - 1];
}
return cleanPath;
}
function resolveCollectionPathIds(path, allCollections) {
let remainingPath = removeInitialAndTrailingSlashes(path);
if (!remainingPath) {
return "";
}
let currentCollections = allCollections;
const resolvedPathParts = [];
while (remainingPath.length > 0) {
if (!currentCollections || currentCollections.length === 0) {
console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
resolvedPathParts.push(remainingPath);
remainingPath = "";
break;
}
let foundMatch = false;
const potentialMatches = currentCollections.flatMap((col) => [{
col,
match: col.path
}, {
col,
match: col.id
}]).filter((p) => p.match && remainingPath.startsWith(p.match)).sort((a, b) => b.match.length - a.match.length);
if (potentialMatches.length > 0) {
const {
col: foundCollection,
match: matchString
} = potentialMatches[0];
resolvedPathParts.push(foundCollection.path);
remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));
if (remainingPath.length === 0) {
foundMatch = true;
break;
}
const idSeparatorIndex = remainingPath.indexOf("/");
let entityId;
if (idSeparatorIndex > -1) {
entityId = remainingPath.substring(0, idSeparatorIndex);
remainingPath = remainingPath.substring(idSeparatorIndex + 1);
} else {
entityId = remainingPath;
remainingPath = "";
console.warn(`resolveCollectionPathIds: Path seems to end with an entity ID "${entityId}" instead of a collection segment in original path "${path}". This might indicate an invalid input path.`);
}
resolvedPathParts.push(entityId);
currentCollections = foundCollection.subcollections;
foundMatch = true;
if (!currentCollections && remainingPath.length > 0) {
console.warn(`resolveCollectionPathIds: Path continues after entity ID "${entityId}", but no subcollections are defined for the preceding collection "${foundCollection.path}" in path "${path}". Appending remaining original path.`);
resolvedPathParts.push(remainingPath);
remainingPath = "";
break;
}
}
if (!foundMatch) {
console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
resolvedPathParts.push(remainingPath);
remainingPath = "";
break;
}
}
return resolvedPathParts.join("/");
}
function getCollectionByPathOrId(pathOrId, collections) {
const subpaths = removeInitialAndTrailingSlashes(pathOrId).split("/");
if (subpaths.length % 2 === 0) {
throw Error(`getCollectionByPathOrId: Collection paths must have an odd number of segments: ${pathOrId}`);
}
const subpathCombinations = getCollectionPathsCombinations(subpaths);
let result;
for (let i = 0; i < subpathCombinations.length; i++) {
const subpathCombination = subpathCombinations[i];
const navigationEntry = collections && collections.sort((a, b) => (a.id ?? "").localeCompare(b.id ?? "")).find((entry) => entry.id === subpathCombination || entry.path === subpathCombination);
if (navigationEntry) {
if (subpathCombination === pathOrId) {
result = navigationEntry;
} else if (navigationEntry.subcollections) {
const newPath = pathOrId.replace(subpathCombination, "").split("/").slice(2).join("/");
if (newPath.length > 0) result = getCollectionByPathOrId(newPath, navigationEntry.subcollections);
}
}
if (result) break;
}
return result;
}
function getCollectionPathsCombinations(subpaths) {
const entries = subpaths.length > 0 && subpaths.length % 2 === 0 ? subpaths.splice(0, subpaths.length - 1) : subpaths;
const length = entries.length;
const result = [];
for (let i = length; i > 0; i = i - 2) {
result.push(entries.slice(0, i).join("/"));
}
return result;
}
function navigateToEntity({
openEntityMode,
collection,
entityId,
copy,
path,
fullIdPath,
selectedTab,
sideEntityController,
onClose,
navigation
}) {
if (openEntityMode === "side_panel") {
sideEntityController.open({
entityId,
path,
fullIdPath,
copy,
selectedTab,
collection,
updateUrl: true,
onClose
});
} else {
let to = navigation.buildUrlCollectionPath(entityId ? `${fullIdPath ?? path}/${entityId}` : fullIdPath ?? path);
if (entityId && selectedTab) {
to += `/${selectedTab}`;
}
if (!entityId) {
to += "#new";
}
if (copy) {
to += "#copy";
}
navigation.navigate(to);
}
}
class EntityReference {
/**
* ID of the entity
*/
id;
/**
* A string representing the path of the referenced document (relative
* to the root of the database).
*/
path;
/**
* Optional database ID where the entity is stored (if multiple databases are used)
*/
databaseId;
constructor(id, path, databaseId) {
this.id = id;
this.path = path;
this.databaseId = databaseId;
}
get pathWithId() {
return `${this.path}/${this.id}`;
}
get pathWithIdAndDatabase() {
if (this.databaseId) {
if (this.databaseId === "(default)") {
return this.pathWithId;
}
return `${this.databaseId}:::${this.path}/${this.id}`;
}
return this.pathWithId;
}
isEntityReference() {
return true;
}
}
class GeoPoint {
/**
* The latitude of this GeoPoint instance.
*/
latitude;
/**
* The longitude of this GeoPoint instance.
*/
longitude;
constructor(latitude, longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
}
class Vector {
value;
constructor(value) {
this.value = value;
}
}
const pick = (obj, ...args) => ({
...args.reduce((res, key) => ({
...res,
[key]: obj[key]
}), {})
});
function isObject(item) {
return item && typeof item === "object" && !Array.isArray(item);
}
function isPlainObject(obj) {
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
return false;
}
const proto = Object.getPrototypeOf(obj);
return proto === Object.prototype;
}
function mergeDeep(target, source, ignoreUndefined = false) {
if (!isObject(target)) {
return target;
}
const output = {
...target
};
if (!isObject(source)) {
return output;
}
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
const sourceValue = source[key];
const outputValue = output[key];
if (ignoreUndefined && sourceValue === void 0) {
continue;
}
if (sourceValue instanceof Date) {
output[key] = new Date(sourceValue.getTime());
} else if (Array.isArray(sourceValue)) {
if (Array.isArray(outputValue)) {
const newArray = [];
const maxLength = Math.max(outputValue.length, sourceValue.length);
for (let i = 0; i < maxLength; i++) {
const sourceItem = sourceValue[i];
const targetItem = outputValue[i];
if (i >= sourceValue.length) {
newArray[i] = targetItem;
} else if (i >= outputValue.length) {
newArray[i] = sourceItem;
} else if (sourceItem === null) {
newArray[i] = targetItem;
} else if (isPlainObject(sourceItem) && isPlainObject(targetItem)) {
newArray[i] = mergeDeep(targetItem, sourceItem, ignoreUndefined);
} else {
newArray[i] = sourceItem;
}
}
output[key] = newArray;
} else {
output[key] = [...sourceValue];
}
} else if (isPlainObject(sourceValue)) {
if (isPlainObject(outputValue)) {
output[key] = mergeDeep(outputValue, sourceValue, ignoreUndefined);
} else {
output[key] = sourceValue;
}
} else if (isObject(sourceValue)) {
output[key] = sourceValue;
} else {
output[key] = sourceValue;
}
}
}
return output;
}
function getValueInPath(o, path) {
if (!o) return void 0;
if (typeof o === "object") {
if (path in o) {
return o[path];
}
if (path.includes(".") || path.includes("[")) {
let pathSegments = path.split(/[.[]/);
if (path.includes("[")) {
pathSegments = pathSegments.map((segment) => segment.replace("]", ""));
}
const firstSegment = pathSegments[0];
const isArrayAndIndexExists = Array.isArray(o[firstSegment]) && !isNaN(parseInt(pathSegments[1]));
const nextObject = isArrayAndIndexExists ? o[firstSegment][parseInt(pathSegments[1])] : o[firstSegment];
const nextPath = pathSegments.slice(isArrayAndIndexExists ? 2 : 1).join(".");
if (nextPath === "") return nextObject;
return getValueInPath(nextObject, nextPath);
}
}
return void 0;
}
function removeInPath(o, path) {
let currentObject = {
...o
};
const parts = path.split(".");
const last = parts.pop();
for (const part of parts) {
currentObject = currentObject[part];
}
if (last) delete currentObject[last];
return currentObject;
}
function removeFunctions(o) {
if (o === void 0) return void 0;
if (o === null) return null;
if (typeof o === "object") {
if (Array.isArray(o)) {
return o.map((v) => removeFunctions(v));
}
if (!isPlainObject(o)) {
return o;
}
return Object.entries(o).filter(([_, value]) => typeof value !== "function").map(([key, value]) => {
if (Array.isArray(value)) {
return {
[key]: value.map((v) => removeFunctions(v))
};
} else if (typeof value === "object") {
return {
[key]: removeFunctions(value)
};
} else return {
[key]: value
};
}).reduce((a, b) => ({
...a,
...b
}), {});
}
return o;
}
function getHashValue(v) {
if (!v) return null;
if (typeof v === "object") {
if ("id" in v) return v.id;
else if (v instanceof Date) return v.toLocaleString();
else if (v instanceof GeoPoint) return hash(v);
}
return hash(v, {
ignoreUnknown: true
});
}
function removeUndefined(value, removeEmptyStrings) {
if (typeof value === "function") {
return value;
}
if (Array.isArray(value)) {
return value.map((v) => removeUndefined(v, removeEmptyStrings));
}
if (typeof value === "object") {
if (value === null) return value;
if (!isPlainObject(value)) {
return value;
}
const res = {};
Object.keys(value).forEach((key) => {
if (!isEmptyObject(value)) {
const childRes = removeUndefined(value[key], removeEmptyStrings);
const isString = typeof childRes === "string";
const shouldKeepIfString = !removeEmptyStrings || removeEmptyStrings && !isString || removeEmptyStrings && isString && childRes !== "";
if (childRes !== void 0 && !isEmptyObject(childRes) && shouldKeepIfString) res[key] = childRes;
}
});
return res;
}
return value;
}
function removeNulls(value) {
if (typeof value === "function") {
return value;
}
if (Array.isArray(value)) {
return value.map((v) => removeNulls(v));
}
if (typeof value === "object") {
if (value === null) return value;
if (!isPlainObject(value)) {
return value;
}
const res = {};
Object.keys(value).forEach((key) => {
if (value[key] !== null) res[key] = removeNulls(value[key]);
});
return res;
}
return value;
}
function isEmptyObject(obj) {
return obj && Object.getPrototypeOf(obj) === Object.prototype && Object.keys(obj).length === 0;
}
function removePropsIfExisting(source, comparison) {
const isObject2 = (val) => typeof val === "object" && val !== null;
const isArray = (val) => Array.isArray(val);
if (!isObject2(source) || !isObject2(comparison)) {
return source;
}
const res = isArray(source) ? [...source] : {
...source
};
if (isArray(res)) {
for (let i = res.length - 1; i >= 0; i--) {
if (res[i] === comparison[i]) {
res.splice(i, 1);
} else if (isObject2(res[i]) && isObject2(comparison[i])) {
res[i] = removePropsIfExisting(res[i], comparison[i]);
}
}
} else {
Object.keys(comparison).forEach((key) => {
if (key in res) {
if (isObject2(res[key]) && isObject2(comparison[key])) {
res[key] = removePropsIfExisting(res[key], comparison[key]);
} else if (res[key] === comparison[key]) {
delete res[key];
}
}
});
}
return res;
}
const DEFAULT_ONE_OF_TYPE = "type";
const DEFAULT_ONE_OF_VALUE = "value";
function isReadOnly(property) {
if (property.readOnly) return true;
if (property.dataType === "date") {
if (property.autoValue) return true;
}
if (property.dataType === "reference") {
return !property.path && !property.Field;
}
return false;
}
function isHidden(property) {
return typeof property.disabled === "object" && Boolean(property.disabled.hidden);
}
function isPropertyBuilder(propertyOrBuilder) {
return typeof propertyOrBuilder === "function";
}
function getDefaultValuesFor(properties) {
if (!properties) return {};
return Object.entries(properties).map(([key, property]) => {
if (!property) return {};
const value = getDefaultValueFor(property);
return value === void 0 ? {} : {
[key]: value
};
}).reduce((a, b) => ({
...a,
...b
}), {});
}
function getDefaultValueFor(property) {
if (!property) return void 0;
if (isPropertyBuilder(property)) return void 0;
if (property.defaultValue || property.defaultValue === null) {
return property.defaultValue;
} else if (property.dataType === "map" && property.properties) {
const defaultValuesFor = getDefaultValuesFor(property.properties);
if (Object.keys(defaultValuesFor).length === 0) return void 0;
return defaultValuesFor;
} else {
return getDefaultValueForDataType(property.dataType);
}
}
function getDefaultValueForDataType(dataType) {
if (dataType === "string") {
return null;
} else if (dataType === "number") {
return null;
} else if (dataType === "boolean") {
return false;
} else if (dataType === "date") {
return null;
} else if (dataType === "array") {
return [];
} else if (dataType === "map") {
return {};
} else {
return null;
}
}
function updateDateAutoValues({
inputValues,
properties,
status,
timestampNowValue
}) {
return traverseValuesProperties(inputValues, properties, (inputValue, property) => {
if (property.dataType === "date") {
if (status === "existing" && property.autoValue === "on_update") {
return timestampNowValue;
} else if ((status === "new" || status === "copy") && (property.autoValue === "on_update" || property.autoValue === "on_create")) {
return timestampNowValue;
} else {
return inputValue;
}
} else {
return inputValue;
}
}) ?? {};
}
function sanitizeData(values, properties) {
const result = values;
Object.entries(properties).forEach(([key, property]) => {
if (values && values[key] !== void 0) result[key] = values[key];
else if (property.validation?.required) result[key] = null;
});
return result;
}
function getReferenceFrom(entity) {
return new EntityReference(entity.id, entity.path, entity.databaseId);
}
function traverseValuesProperties(inputValues, properties, operation) {
const safeInputValues = inputValues ?? {};
const updatedValues = Object.entries(properties).map(([key, property]) => {
const inputValue = safeInputValues && safeInputValues[key];
const updatedValue = traverseValueProperty(inputValue, property, operation);
if (updatedValue === null) return null;
if (updatedValue === void 0) return void 0;
return {
[key]: updatedValue
};
}).reduce((a, b) => ({
...a,
...b
}), {});
const result = mergeDeep(safeInputValues, updatedValues);
if (!result || Object.keys(result).length === 0) return void 0;
return result;
}
function traverseValueProperty(inputValue, property, operation) {
let value;
if (property.dataType === "map" && property.properties) {
value = traverseValuesProperties(inputValue, property.properties, operation);
} else if (property.dataType === "array") {
if (property.of && Array.isArray(inputValue)) {
value = inputValue.map((e) => traverseValueProperty(e, property.of, operation));
} else if (property.oneOf && Array.isArray(inputValue)) {
const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;
const valueField = property.oneOf?.valueField ?? DEFAULT_ONE_OF_VALUE;
value = inputValue.map((e) => {
if (e === null) return null;
if (typeof e !== "object") return e;
const type = e[typeField];
const childProperty = property.oneOf?.properties[type];
if (!type || !childProperty) return e;
return {
[typeField]: type,
[valueField]: traverseValueProperty(e[valueField], childProperty, operation)
};
});
} else {
value = inputValue;
}
} else {
value = operation(inputValue, property);
}
return value;
}
function enumToObjectEntries(enumValues) {
if (Array.isArray(enumValues)) {
return enumValues;
} else {
return Object.entries(enumValues).map(([id, value]) => {
if (typeof value === "string") {
return {
id,
label: value
};
} else {
return {
...value,
id
};
}
});
}
}
function getLabelOrConfigFrom(enumValues, key) {
if (key === null || key === void 0) return void 0;
return enumValues.find((entry) => String(entry.id) === String(key));
}
function getColorScheme(enumValues, key) {
const labelOrConfig = getLabelOrConfigFrom(enumValues, key);
if (!labelOrConfig?.color) return getColorSchemeForSeed(key.toString());
if (typeof labelOrConfig === "object" && "color" in labelOrConfig) {
if (typeof labelOrConfig.color === "string") return CHIP_COLORS[labelOrConfig.color];
if (typeof labelOrConfig.color === "object") return labelOrConfig.color;
}
return void 0;
}
function isEnumValueDisabled(labelOrConfig) {
return typeof labelOrConfig === "object" && labelOrConfig.disabled;
}
function buildEnumLabel(labelOrConfig) {
if (labelOrConfig === void 0) return void 0;
if (typeof labelOrConfig === "object") {
return labelOrConfig.label;
} else {
return labelOrConfig;
}
}
const resolveCollection = ({
collection,
path,
entityId,
values,
previousValues,
userConfigPersistence,
propertyConfigs,
ignoreMissingFields = false,
authController
}) => {
const collectionOverride = userConfigPersistence?.getCollectionConfig(path);
const storedProperties = getValueInPath(collectionOverride, "properties");
const defaultValues = getDefaultValuesFor(collection.properties);
const usedValues = values ?? defaultValues;
const usedPreviousValues = previousValues ?? values ?? defaultValues;
const resolvedProperties = Object.entries(collection.properties).filter(([, propertyOrBuilder]) => propertyOrBuilder != null).map(([key, propertyOrBuilder]) => {
const childResolvedProperty = resolveProperty({
propertyKey: key,
propertyOrBuilder,
values: usedValues,
previousValues: usedPreviousValues,
path,
entityId,
propertyConfigs,
ignoreMissingFields,
authController
});
if (!childResolvedProperty) return {};
return {
[key]: childResolvedProperty
};
}).filter((a) => a !== null).reduce((a, b) => ({
...a,
...b
}), {});
const properties = mergeDeep(resolvedProperties, storedProperties);
const cleanedProperties = Object.entries(properties).filter(([_, property]) => Boolean(property?.dataType)).map(([id, property]) => ({
[id]: property
})).reduce((a, b) => ({
...a,
...b
}), {});
return {
...collection,
properties: cleanedProperties,
originalCollection: collection
};
};
function resolveProperty({
propertyOrBuilder,
fromBuilder = false,
ignoreMissingFields = false,
...props
}) {
if (propertyOrBuilder !== null && typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
return propertyOrBuilder;
}
let resolvedProperty = null;
if (!propertyOrBuilder) {
return null;
} else if (isPropertyBuilder(propertyOrBuilder)) {
const path = props.path;
if (!path) throw Error("Trying to resolve a property builder without specifying the entity path");
const usedPropertyValue = props.propertyKey ? getIn(props.values, props.propertyKey) : void 0;
const result = propertyOrBuilder({
...props,
path,
propertyValue: usedPropertyValue,
values: props.values ?? {},
previousValues: props.previousValues ?? props.values ?? {}
});
if (!result) {
return null;
}
resolvedProperty = resolveProperty({
...props,
propertyOrBuilder: result,
fromBuilder: true,
ignoreMissingFields
});
} else {
const property = propertyOrBuilder;
if (property.dataType === "map" && property.properties) {
const properties = resolveProperties({
ignoreMissingFields,
...props,
properties: property.properties
});
resolvedProperty = {
...property,
resolved: true,
fromBuilder,
properties
};
} else if (property.dataType === "array") {
resolvedProperty = resolveArrayProperty({
property,
fromBuilder,
ignoreMissingFields,
...props
});
} else if ((property.dataType === "string" || property.dataType === "number") && property.enumValues) {
resolvedProperty = resolvePropertyEnum(property, fromBuilder);
}
}
if (!resolvedProperty) {
resolvedProperty = {
...propertyOrBuilder,
resolved: true,
fromBuilder
};
}
if (resolvedProperty.propertyConfig && !isDefaultFieldConfigId(resolvedProperty.propertyConfig)) {
const cmsFields = props.propertyConfigs;
if (!cmsFields && !ignoreMissingFields) {
throw Error(`Trying to resolve a property with key '${resolvedProperty.propertyConfig}' that inherits from a custom property config but no custom property configs were provided. Use the property 'propertyConfigs' in your app config to provide them`);
}
const customField = cmsFields?.[resolvedProperty.propertyConfig];
if (!customField) {
console.warn(`Trying to resolve a property with key '${resolvedProperty.propertyConfig}' that inherits from a custom property config but no custom property config with that key was found. Check the 'propertyConfigs' in your app config`);
console.warn("Available property configs", cmsFields);
return null;
}
if (customField.property) {
const configPropertyOrBuilder = customField.property;
if ("propertyConfig" in configPropertyOrBuilder) {
delete configPropertyOrBuilder.propertyConfig;
}
const customFieldProperty = resolveProperty({
propertyOrBuilder: configPropertyOrBuilder,
ignoreMissingFields,
...props
});
if (customFieldProperty) {
resolvedProperty = mergeDeep(customFieldProperty, resolvedProperty);
}
}
}
return resolvedProperty ? {
...resolvedProperty,
resolved: true
} : null;
}
function getArrayResolvedProperties({
propertyKey,
propertyValue,
property,
...props
}) {
const of = property.of;
return Array.isArray(propertyValue) ? propertyValue.map((v, index) => {
return resolveProperty({
propertyKey: `${propertyKey}.${index}`,
propertyOrBuilder: of,
...props,
index
});
}).filter((e) => Boolean(e)) : [];
}
function resolveArrayProperty({
propertyKey,
property,
ignoreMissingFields = false,
...props
}) {
const propertyValue = propertyKey ? getIn(props.values, propertyKey) : void 0;
if (property.of) {
if (Array.isArray(property.of)) {
return {
...property,
resolved: true,
fromBuilder: props.fromBuilder,
resolvedProperties: property.of.map((p, index) => {
return resolveProperty({
propertyKey: `${propertyKey}.${index}`,
propertyOrBuilder: p,
ignoreMissingFields,
...props,
index
});
})
};
} else {
const of = property.of;
const resolvedProperties = getArrayResolvedProperties({
propertyValue,
propertyKey,
property,
ignoreMissingFields,
...props
});
const ofProperty = resolveProperty({
propertyOrBuilder: of,
ignoreMissingFields,
...props
});
if (!ofProperty && !ignoreMissingFields) throw Error("When using a property builder as the 'of' prop of an ArrayProperty, you must return a valid child property");
return {
...property,
resolved: true,
fromBuilder: props.fromBuilder,
of: ofProperty,
resolvedProperties
};
}
} else if (property.oneOf) {
const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;
const resolvedProperties = Array.isArray(propertyValue) ? propertyValue.map((v, index) => {
const type = v && v[typeField];
const childProperty = property.oneOf?.properties[type];
if (!type || !childProperty) return null;
return resolveProperty({
propertyKey: `${propertyKey}.${index}`,
propertyOrBuilder: childProperty,
ignoreMissingFields,
...props
});
}).filter((e) => Boolean(e)) : [];
const properties = resolveProperties({
propertyKey,
properties: property.oneOf.properties,
ignoreMissingFields,
...props
});
return {
...property,
resolved: true,
oneOf: {
...property.oneOf,
properties
},
fromBuilder: props.fromBuilder,
resolvedProperties
};
} else if (!property.Field) {
console.error("The array property needs to declare an 'of' or a 'oneOf' property, or provide a custom `Field`", property);
return null;
} else {
return {
...property,
resolved: true,
fromBuilder: props.fromBuilder
};
}
}
function resolveProperties({
propertyKey,
properties,
ignoreMissingFields,
...props
}) {
return Object.entries(properties).map(([key, property]) => {
const childResolvedProperty = resolveProperty({
propertyKey: propertyKey ? `${propertyKey}.${key}` : void 0,
propertyOrBuilder: property,
ignoreMissingFields,
...props
});
if (!childResolvedProperty) return {};
return {
[key]: childResolvedProperty
};
}).filter((a) => a !== null).reduce((a, b) => ({
...a,
...b
}), {});
}
function resolvePropertyEnum(property, fromBuilder) {
if (typeof property.enumValues === "object") {
return {
...property,
resolved: true,
enumValues: enumToObjectEntries(property.enumValues)?.filter((value) => value && (value.id || value.id === 0) && value.label) ?? [],
fromBuilder: fromBuilder ?? false
};
}
return property;
}
function resolveEnumValues(input) {
if (Array.isArray(input)) {
return input;
} else if (typeof input === "object" && input !== null) {
return Object.entries(input).map(([id, value]) => typeof value === "string" ? {
id,
label: value
} : value);
} else {
return void 0;
}
}
function resolveEntityView(entityView, contextEntityViews) {
if (typeof entityView === "string") {
return contextEntityViews?.find((entry) => entry.key === entityView);
} else {
return entityView;
}
}
function resolveEntityAction(entityAction, contextEntityActions) {
if (typeof entityAction === "string") {
return contextEntityActions?.find((entry) => entry.key === entityAction);
} else {
return entityAction;
}
}
function resolvedSelectedEntityView(customViews, customizationController, selectedTab, canEdit) {
const resolvedEntityViews = customViews ? customViews.map((e) => resolveEntityView(e, customizationController.entityViews)).filter((e) => Boolean(e)) : [];
const selectedEntityView = resolvedEntityViews.find((e) => e.key === selectedTab);
const selectedSecondaryForm = customViews && resolvedEntityViews.filter((e) => e.includeActions).find((e) => e.key === selectedTab);
return {
resolvedEntityViews,
selectedEntityView,
selectedSecondaryForm
};
}
function getNavigationEntriesFromPath(props) {
const {
path,
collections = [],
currentFullPath,
currentFullIdPath
} = props;
const subpaths = removeInitialAndTrailingSlashes(path).split("/");
const subpathCombinations = getCollectionPathsCombinations(subpaths);
const result = [];
for (let i = 0; i < subpathCombinations.length; i++) {
const subpathCombination = subpathCombinations[i];
let collection;
collection = collections && collections.find((entry) => entry.id === subpathCombination);
if (!collection) {
collection = collections && collections.find((entry) => entry.path === subpathCombination);
}
if (collection) {
const collectionPath = currentFullPath && currentFullPath.length > 0 ? currentFullPath + "/" + collection.path : collection.path;
const fullIdPath = currentFullIdPath && currentFullIdPath.length > 0 ? currentFullIdPath + "/" + collection.id : collection.id;
result.push({
type: "collection",
id: collection.id,
path: collectionPath,
fullPath: collectionPath,
fullIdPath,
collection
});
const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, ""));
const nextSegments = restOfThePath.length > 0 ? restOfThePath.split("/") : [];
if (nextSegments.length > 0) {
const entityId = nextSegments[0];
const fullPath = collectionPath + "/" + entityId;
result.push({
type: "entity",
entityId,
path: collectionPath,
fullIdPath,
fullPath,
parentCollection: collection
});
if (nextSegments.length > 1) {
const newPath = nextSegments.slice(1).join("/");
if (!collection) {
throw Error("collection not found resolving path: " + collection);
}
const entityViews = collection.entityViews;
const customView = entityViews && entityViews.map((entry) => resolveEntityView(entry, props.contextEntityViews)).filter(Boolean).find((entry) => entry.key === newPath);
if (customView) {
result.push({
type: "custom_view",
path: collectionPath,
entityId,
fullIdPath,
fullPath: fullPath + "/" + customView.key,
view: customView
});
} else if (collection.subcollections) {
result.push(...getNavigationEntriesFromPath({
path: newPath,
collections: collection.subcollections,
currentFullPath: fullPath,
currentFullIdPath: fullIdPath,
contextEntityViews: props.contextEntityViews
}));
}
}
}
break;
}
}
return result;
}
function sortProperties(properties, propertiesOrder) {
try {
const propertiesKeys = Object.keys(properties);
if (!propertiesOrder || propertiesOrder.length === 0) {
return propertiesKeys.map((key) => {
const property = properties[key];
if (!isPropertyBuilder(property) && property?.dataType === "map" && property.properties) {
return {
[key]: {
...property,
properties: sortProperties(property.properties, property.propertiesOrder)
}
};
} else {
return {
[key]: property
};
}
}).reduce((a, b) => ({
...a,
...b
}), {});
}
const validOrderKeys = propertiesOrder.filter((key) => {
return !key.includes(".") && properties[key];
});
const processedKeys = new Set(validOrderKeys);
const orderedResult = validOrderKeys.map((key) => {
const property = properties[key];
if (!isPropertyBuilder(property) && property?.dataType === "map" && property.properties) {
return {
[key]: {
...property,
properties: sortProperties(property.properties, property.propertiesOrder)
}
};
} else {
return {
[key]: property
};
}
}).reduce((a, b) => ({
...a,
...b
}), {});
const missingProperties = propertiesKeys.filter((key) => !processedKeys.has(key)).map((key) => {
const property = properties[key];
if (!isPropertyBuilder(property) && property?.dataType === "map" && property.properties) {
return {
[key]: {
...property,
properties: sortProperties(property.properties, property.propertiesOrder)
}
};
} else {
return {
[key]: property
};
}
}).reduce((a, b) => ({
...a,
...b
}), {});
return {
...orderedResult,
...missingProperties
};
} catch (e) {
console.error("Error sorting properties", e);
return properties;
}
}
function resolveDefaultSelectedView(defaultSelectedView, params) {
if (!defaultSelectedView) {
return void 0;
} else if (typeof defaultSelectedView === "string") {
return defaultSelectedView;
} else {
return defaultSelectedView(params);
}
}
const applyPermissionsFunctionIfEmpty = (collections, permissionsBuilder) => {
return collections.map((collection) => {
if (collection.permissions) {
return collection;
}
return {
...collection,
permissions: permissionsBuilder
};
});
};
function getLocalChangesBackup(collection) {
if (!collection.localChangesBackup) {
return "manual_apply";
}
return collection.localChangesBackup;
}
const kebabCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
const toKebabCase = (str) => {
const regExpMatchArray = str.match(kebabCaseRegex);
if (!regExpMatchArray) return "";
return regExpMatchArray.map((x) => x.toLowerCase()).join("-");
};
const snakeCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
const toSnakeCase = (str) => {
const regExpMatchArray = str.match(snakeCaseRegex);
if (!regExpMatchArray) return "";
return regExpMatchArray.map((x) => x.toLowerCase()).join("_");
};
function randomString(strLength = 5) {
return Math.random().toString(36).slice(2, 2 + strLength);
}
function randomColor() {
return Math.floor(Math.random() * 16777215).toString(16);
}
function slugify(text, separator = "_", lowercase = true) {
if (!text) return "";
const from = "ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;-";
const to = `aaaaaeeeeeiiiiooooouuuunc${separator}${separator}${separator}${separator}${separator}${separator}${separator}`;
for (let i = 0, l = from.length; i < l; i++) {
text = text.replace(new RegExp(from.charAt(i), "g"), to.charAt(i));
}
text = text.toString().replace(/\s+/g, separator).replace(/&/g, separator).replace(/[^\w\\-]+/g, "").replace(new RegExp("\\" + separator + "\\" + separator + "+", "g"), separator).trim().replace(/^\s+|\s+$/g, "");
return lowercase ? text.toLowerCase() : text;
}
function unslugify(slug) {
if (!slug) return "";
if (slug.includes("-") || slug.includes("_") || !slug.includes(" ")) {
const result = slug.replace(/[-_]/g, " ");
return result.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1);
}).trim();
} else {
return slug.trim();
}
}
function prettifyIdentifier(input) {
if (!input) return "";
let text = input;
text = text.replace(/([a-z])([A-Z])|([A-Z])([A-Z][a-z])/g, "$1$3 $2$4");
text = text.replace(/[_-]+/g, " ");
const s = text.trim().replace(/\b\w/g, (char) => char.toUpperCase());
console.log("Prettified identifier:", {
input,
s
});
return s;
}
const defaultDateFormat = "MMMM dd, yyyy, HH:mm:ss";
const COLLECTION_PATH_SEPARATOR = "::";
function stripCollectionPath(path) {
return segmentsToStrippedPath(fullPathToCollectionSegments(path));
}
function segmentsToStrippedPath(paths) {
if (paths.length === 1) return paths[0];
return paths.reduce((a, b) => `${a}${COLLECTION_PATH_SEPARATOR}${b}`);
}
function fullPathToCollectionSegments(path) {
return path.split("/").filter((e, i) => i % 2 === 0);
}
function serializeRegExp(input) {
if (!input) return "";
return input.toString();
}
function hydrateRegExp(input) {
if (!input) return void 0;
const fragments = input.match(/\/(.*?)\/([a-z]*)?$/i);
if (fragments) {
return new RegExp(fragments[1], fragments[2] || "");
} else {
return new RegExp(input, "");
}
}
function isValidRegExp(input) {
const fullRegexp = input.match(/\/((?![*+?])(?:[^\r\n[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*])+)\/((?:g(?:im?|mi?)?|i(?:gm?|mg?)?|m(?:gi?|ig?)?)?)/);
if (fullRegexp) return true;
const simpleRegexp = input.match(/((?![*+?])(?:[^\r\n[/\\]|\\.|\[(?:[^\r\n\]\\]|\\.)*])+)/);
return !!simpleRegexp;
}
const reservedKeys = ["edit", "copy", "delete"];
function mergeEntityActions(currentActions, newActions) {
const updatedActions = [];
currentActions.forEach((action) => {
const newAction = newActions.find((a) => a.key === action.key);
if (newAction) {
const mergedAction = {
...action,
...newAction
};
updatedActions.push(mergedAction);
} else {
updatedActions.push(action);
}
});
newActions.forEach((action) => {
if (!currentActions.find((a) => a.key === action.key) && (!action.key || !reservedKeys.includes(action.key))) {
updatedActions.push(action);
}
});
return updatedActions;
}
function useDebouncedCallback(value, callback, immediate, t0) {
const $ = c(9);
const timeoutMs = t0 === void 0 ? 300 : t0;
const pendingUpdate = React__default.useRef(false);
let t1;
if ($[0] !== callback) {
t1 = () => {
callback();
pendingUpdate.current = false;
};
$[0] = callback;
$[1] = t1;
} else {
t1 = $[1];
}
const performUpdate = t1;
const handlerRef = React__default.useRef(void 0);
let t2;
if ($[2] !== immediate || $[3] !== performUpdate || $[4] !== timeoutMs) {
t2 = () => {
pendingUpdate.current = true;
clearTimeout(handlerRef.current);
handlerRef.current = setTimeout(performUpdate, timeoutMs);
return () => {
if (immediate) {
performUpdate();
}
};
};
$[2] = immediate;
$[3] = performUpdate;
$[4] = timeoutMs;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== immediate || $[7] !== value) {
t3 = [immediate, value];
$[6] = immediate;
$[7] = value;
$[8] = t3;
} else {
t3 = $[8];
}
React__default.useEffect(t2, t3);
}
function isReferenceProperty(authController, propertyOrBuilder, fields) {
const resolvedProperty = resolveProperty({
propertyKey: "ignore",
// TODO
propertyOrBuilder,
propertyConfigs: fields,
authController
});
if (!resolvedProperty) return null;
if (resolvedProperty.dataType === "reference") {
return true;
}
if (resolvedProperty.dataType === "array") {
if (Array.isArray(resolvedProperty.of)) return false;
else return resolvedProperty.of?.dataType === "reference";
}
return false;
}
function getIdIcon(size) {
return /* @__PURE__ */ jsx(CircleIcon, { size });
}
function getIconForWidget(widget, size) {
const Icon2 = widget?.Icon ?? CircleIcon;
return /* @__PURE__ */ jsx(Icon2, { size });
}
function getIconForProperty(property, size = "small", fields = {}) {
if (isPropertyBuilder(property)) {
return /* @