@rebasepro/app 0.12.0 → 0.12.1-canary.g009ed95
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/README.md +1 -1
- package/dist/auth/api.d.ts +3 -8
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/types.d.ts +1 -5
- package/dist/collections/form-layout.d.ts +107 -0
- package/dist/collections/index.d.ts +1 -0
- package/dist/collections/title-property.d.ts +22 -0
- package/dist/components/Debug/collection-views/sample_data.d.ts +3 -2
- package/dist/hooks/ApiConfigContext.d.ts +36 -2
- package/dist/hooks/useBackendStorageSource.d.ts +6 -1
- package/dist/hooks/useNavigationBlocker.d.ts +1 -1
- package/dist/hooks/useSnackbarController.d.ts +2 -1
- package/dist/hooks/useStudioBridge.d.ts +27 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +667 -186
- package/dist/index.es.js.map +1 -1
- package/dist/internal/common.d.ts +14 -2
- package/package.json +29 -25
- package/src/auth/api.ts +8 -9
- package/src/auth/index.ts +2 -2
- package/src/auth/types.ts +5 -6
- package/src/collections/form-layout.ts +386 -0
- package/src/collections/index.ts +1 -0
- package/src/collections/title-property.ts +41 -0
- package/src/components/Debug/UIReferenceView.tsx +9 -1
- package/src/components/Debug/collection-views/sample_data.ts +4 -2
- package/src/components/NotFoundPage.tsx +1 -1
- package/src/components/common/useDataTableController.tsx +1 -1
- package/src/core/Rebase.tsx +5 -1
- package/src/core/RebaseRouter.tsx +2 -1
- package/src/core/RebaseRoutes.tsx +1 -1
- package/src/hooks/ApiConfigContext.tsx +45 -3
- package/src/hooks/useAuthSubscription.ts +29 -3
- package/src/hooks/useBackendStorageSource.ts +8 -1
- package/src/hooks/useNavigationBlocker.tsx +1 -1
- package/src/hooks/useSnackbarController.tsx +34 -6
- package/src/hooks/useStudioBridge.tsx +50 -2
- package/src/index.ts +1 -1
- package/src/internal/common.tsx +15 -3
- package/src/internal/useRestoreScroll.tsx +1 -1
- package/src/locales/de.ts +21 -2
- package/src/locales/en.ts +21 -1
- package/src/locales/es.ts +21 -1
- package/src/locales/fr.ts +21 -1
- package/src/locales/hi.ts +21 -1
- package/src/locales/it.ts +21 -1
- package/src/locales/pt.ts +21 -1
- package/src/util/enums.ts +4 -2
- package/src/util/useStorageUploadController.tsx +5 -1
package/dist/index.es.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import React, { createContext, lazy, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
|
-
import { Alert, AlertCircleIcon, AlertTriangleIcon, AppWindow, ArrowDownIcon, ArrowLeftIcon, ArrowRightLeftIcon, ArrowUpDownIcon, ArrowUpIcon, Avatar, BooleanSwitch, Button,
|
|
2
|
+
import { Alert, AlertCircleIcon, AlertTriangleIcon, AppWindow, ArrowDownIcon, ArrowLeftIcon, ArrowRightLeftIcon, ArrowUpDownIcon, ArrowUpIcon, Avatar, BooleanSwitch, Button, CalendarIcon, Card, CenteredView, CheckCircle2Icon, CheckIcon, Checkbox, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon, Chip, CircleDotIcon, CircleUserIcon, CircularProgress, ColumnsIcon, Container, Dialog, DialogActions, DialogContent, DialogTitle, DollarSignIcon, ErrorBoundary, FileIcon, FileTextIcon, FilterChip, FilterIcon, FolderIcon, FolderKanbanIcon, IconButton, KanbanIcon, KanbanView, LanguagesIcon, LayoutGridIcon, ListIcon, ListPlusIcon, ListTodoIcon, LoadingButton, LogOutIcon, MailIcon, Menu, MenuItem, MessageCircleIcon, MoonIcon, MultiSelect, MultiSelectItem, PanelLeftIcon, Paper, PenLineIcon, PencilIcon, PhoneIcon, PinIcon, PlusIcon, Popover, RefreshCwIcon, SearchBar, Select, SelectItem, Separator, SettingsIcon, Skeleton, StickyNoteIcon, SunIcon, SunMoonIcon, Tab, Table, TableBody, TableCell, TableHeader, TableRow, Tabs, TagIcon, TextField, ToggleButtonGroup, Tooltip, Trash2Icon, TrendingUpIcon, TypeIcon, Typography, UserIcon, UserPlus, UsersIcon, VideoIcon, Wand2Icon, WrenchIcon, XIcon, cls, colorClassesMapping, coolIconKeys, defaultBorderMixin, getColorSchemeForKey, getColorSchemeForSeed, iconKeys, iconSize, lucideIcons } from "@rebasepro/ui";
|
|
3
3
|
import { ALL_WHERE_FILTER_OPS, DEFAULT_DATA_SOURCE_KEY, DEFAULT_FILTERABLE_RELATION_KINDS, DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, RebaseApiError, Vector, getDataSourceCapabilities, isLazyComponentRef, isRelationalCollectionConfig } from "@rebasepro/types";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { SnackbarProvider as SnackbarProvider$1, useSnackbar } from "notistack";
|
|
6
6
|
import { buildRebaseData, canCreateEntity, canDeleteEntity, canEditEntity, canReadCollection, evaluateCondition, getEntityChildViews, getLabelOrConfigFrom, getPrimaryKeys, getSubcollections, isPropertyBuilder, resolveStorageFilenameString, resolveStoragePathString, resolveStorageSource, stripCollectionPath, wrapAsEntityData, wrapAsSdkData } from "@rebasepro/common";
|
|
7
7
|
import { getTitlePropertyKey as getTitlePropertyKey$1, removeInitialAndTrailingSlashes as removeInitialAndTrailingSlashes$1 } from "@rebasepro/app";
|
|
8
|
-
import { Link,
|
|
8
|
+
import { Link, Routes, createBrowserRouter, useBlocker, useLocation } from "react-router";
|
|
9
9
|
import { generateForeignKeyName, hashString, isObject, isPlainObject, mergeDeep, randomString, slugify } from "@rebasepro/utils";
|
|
10
10
|
import { I18nextProvider, initReactI18next, useTranslation as useTranslation$1 } from "react-i18next";
|
|
11
11
|
import { deepEqual } from "fast-equals";
|
|
12
12
|
import i18next from "i18next";
|
|
13
|
+
import { RouterProvider } from "react-router/dom";
|
|
13
14
|
import Fuse from "fuse.js";
|
|
14
15
|
import Compressor from "compressorjs";
|
|
15
16
|
import { resolveAdminCollection } from "@rebasepro/admin-types";
|
|
@@ -162,12 +163,15 @@ var DialogsProvider = ({ children }) => {
|
|
|
162
163
|
};
|
|
163
164
|
const close = useCallback(() => {
|
|
164
165
|
if (dialogEntries.length === 0) return;
|
|
165
|
-
|
|
166
|
+
const updatedPanels = [...dialogEntriesRef.current.slice(0, -1)];
|
|
167
|
+
updateDialogEntries(updatedPanels);
|
|
166
168
|
}, [dialogEntries]);
|
|
167
169
|
const open = useCallback((dialogEntry) => {
|
|
168
|
-
|
|
170
|
+
const updatedPanels = [...dialogEntriesRef.current, dialogEntry];
|
|
171
|
+
updateDialogEntries(updatedPanels);
|
|
169
172
|
return { closeDialog: () => {
|
|
170
|
-
|
|
173
|
+
const updatedPanels = dialogEntriesRef.current.filter((e) => e.key !== dialogEntry.key);
|
|
174
|
+
updateDialogEntries(updatedPanels);
|
|
171
175
|
} };
|
|
172
176
|
}, [dialogEntries]);
|
|
173
177
|
const dialogsController = useMemo(() => ({
|
|
@@ -624,24 +628,37 @@ var useStorageSource = () => {
|
|
|
624
628
|
var useSnackbarController = () => {
|
|
625
629
|
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
|
|
626
630
|
const open = useCallback((props) => {
|
|
627
|
-
const { type, message, autoHideDuration } = props;
|
|
631
|
+
const { type, message, autoHideDuration, action } = props;
|
|
628
632
|
enqueueSnackbar({
|
|
629
633
|
message: props.title ? /* @__PURE__ */ jsxs("div", {
|
|
630
634
|
className: "flex flex-col",
|
|
631
635
|
children: [/* @__PURE__ */ jsx("strong", { children: props.title }), message]
|
|
632
636
|
}) : message,
|
|
633
637
|
variant: type,
|
|
634
|
-
autoHideDuration
|
|
638
|
+
autoHideDuration,
|
|
639
|
+
...action ? { key: nextActionKey() } : {},
|
|
640
|
+
action: action ? (key) => /* @__PURE__ */ jsx(Button, {
|
|
641
|
+
variant: "text",
|
|
642
|
+
size: "small",
|
|
643
|
+
className: "text-inherit",
|
|
644
|
+
onClick: () => {
|
|
645
|
+
action.onClick();
|
|
646
|
+
closeSnackbar(key);
|
|
647
|
+
},
|
|
648
|
+
children: action.label
|
|
649
|
+
}) : void 0
|
|
635
650
|
});
|
|
636
|
-
}, []);
|
|
651
|
+
}, [enqueueSnackbar, closeSnackbar]);
|
|
637
652
|
const close = useCallback(() => {
|
|
638
653
|
closeSnackbar();
|
|
639
|
-
}, []);
|
|
654
|
+
}, [closeSnackbar]);
|
|
640
655
|
return useMemo(() => ({
|
|
641
656
|
open,
|
|
642
657
|
close
|
|
643
658
|
}), [open, close]);
|
|
644
659
|
};
|
|
660
|
+
var actionKeySeq = 0;
|
|
661
|
+
var nextActionKey = () => `rebase-snackbar-action-${actionKeySeq++}`;
|
|
645
662
|
//#endregion
|
|
646
663
|
//#region src/hooks/useUserConfigurationPersistence.tsx
|
|
647
664
|
/**
|
|
@@ -908,7 +925,8 @@ function useRelationSelector({ path, collection, fixedFilter, pageSize = DEFAULT
|
|
|
908
925
|
setLoading(true);
|
|
909
926
|
const whereParams = fixedFilter && Object.keys(fixedFilter).length > 0 ? fixedFilter : void 0;
|
|
910
927
|
const onEntitiesUpdate = (res) => {
|
|
911
|
-
|
|
928
|
+
const newItems = res.data.map((e) => entityToRelationItem(e));
|
|
929
|
+
setItems(newItems);
|
|
912
930
|
setHasMore(res.meta.hasMore);
|
|
913
931
|
setLoading(false);
|
|
914
932
|
};
|
|
@@ -1201,14 +1219,38 @@ function useUnsavedChangesDialog(when, onOk) {
|
|
|
1201
1219
|
function useAuthSubscription(authClient) {
|
|
1202
1220
|
const currentSession = authClient?.getSession();
|
|
1203
1221
|
const [user, setUser] = useState(currentSession?.user ?? null);
|
|
1204
|
-
const [initialLoading, setInitialLoading] = useState(!currentSession);
|
|
1205
1222
|
const [authLoading, setAuthLoading] = useState(false);
|
|
1206
1223
|
const [authError, setAuthError] = useState();
|
|
1207
1224
|
const [loginSkipped, setLoginSkipped] = useState(false);
|
|
1208
1225
|
const [extra, setExtra] = useState();
|
|
1226
|
+
/**
|
|
1227
|
+
* Whether asking the server "who am I?" could possibly answer.
|
|
1228
|
+
*
|
|
1229
|
+
* A client configured with `persistSession: false` and JSON auth — the
|
|
1230
|
+
* shape used when one client borrows another's credential, as the hosted
|
|
1231
|
+
* Studio does — has no stored session and no auth cookie, so the probe
|
|
1232
|
+
* below is guaranteed to 401. Sending it anyway put three failing
|
|
1233
|
+
* `GET /auth/me` calls on the wire per mount, each one landing in the
|
|
1234
|
+
* *customer's* request log as an authentication failure against their own
|
|
1235
|
+
* backend.
|
|
1236
|
+
*
|
|
1237
|
+
* A client that does not implement the capability is treated as "might
|
|
1238
|
+
* work" — the historical behaviour.
|
|
1239
|
+
*/
|
|
1240
|
+
const mayHaveRestorableSession = authClient?.canRestoreSession?.() ?? true;
|
|
1241
|
+
/**
|
|
1242
|
+
* `true` only while a probe is genuinely outstanding.
|
|
1243
|
+
*
|
|
1244
|
+
* It used to be seeded from `!currentSession` alone, which left a client
|
|
1245
|
+
* that cannot restore a session — and therefore never runs the probe that
|
|
1246
|
+
* clears the flag — reporting "still loading" forever. Anything gated on
|
|
1247
|
+
* `initialLoading` (a spinner, a redirect to the login view) would never
|
|
1248
|
+
* resolve.
|
|
1249
|
+
*/
|
|
1250
|
+
const [initialLoading, setInitialLoading] = useState(!currentSession && mayHaveRestorableSession);
|
|
1209
1251
|
useEffect(() => {
|
|
1210
1252
|
if (!authClient) return;
|
|
1211
|
-
if (!currentSession) {
|
|
1253
|
+
if (!currentSession && mayHaveRestorableSession) {
|
|
1212
1254
|
setInitialLoading(true);
|
|
1213
1255
|
authClient.getUser().then((user) => {
|
|
1214
1256
|
if (user) setUser(user);
|
|
@@ -1216,7 +1258,11 @@ function useAuthSubscription(authClient) {
|
|
|
1216
1258
|
setInitialLoading(false);
|
|
1217
1259
|
});
|
|
1218
1260
|
}
|
|
1219
|
-
}, [
|
|
1261
|
+
}, [
|
|
1262
|
+
authClient,
|
|
1263
|
+
currentSession,
|
|
1264
|
+
mayHaveRestorableSession
|
|
1265
|
+
]);
|
|
1220
1266
|
useEffect(() => {
|
|
1221
1267
|
if (!authClient) return;
|
|
1222
1268
|
return authClient.onAuthStateChange((event, session) => {
|
|
@@ -1751,6 +1797,60 @@ function useRebaseRegistryDispatch() {
|
|
|
1751
1797
|
return dispatch;
|
|
1752
1798
|
}
|
|
1753
1799
|
//#endregion
|
|
1800
|
+
//#region src/hooks/ApiConfigContext.tsx
|
|
1801
|
+
/** What the server uses when `basePath` is not configured. */
|
|
1802
|
+
var DEFAULT_API_PATH = "/api";
|
|
1803
|
+
var ApiConfigContext = React.createContext(void 0);
|
|
1804
|
+
/**
|
|
1805
|
+
* Read the API config from context. Returns `undefined` if no provider is present,
|
|
1806
|
+
* allowing hooks to fall back to their own props.
|
|
1807
|
+
*/
|
|
1808
|
+
function useApiConfig() {
|
|
1809
|
+
return useContext(ApiConfigContext);
|
|
1810
|
+
}
|
|
1811
|
+
/**
|
|
1812
|
+
* `apiUrl` and `apiPath` joined, with no trailing slash — the prefix to build a
|
|
1813
|
+
* request URL from.
|
|
1814
|
+
*
|
|
1815
|
+
* Returns `undefined` when there is no provider, so a caller can keep its own
|
|
1816
|
+
* fallback rather than silently requesting a relative path.
|
|
1817
|
+
*/
|
|
1818
|
+
function useApiBase() {
|
|
1819
|
+
const config = useApiConfig();
|
|
1820
|
+
if (!config?.apiUrl) return void 0;
|
|
1821
|
+
return config.apiUrl.replace(/\/+$/, "") + (config.apiPath || "/api");
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* The same prefix, derived from a client rather than from context.
|
|
1825
|
+
*
|
|
1826
|
+
* For the code that holds a `RebaseClient` but sits outside (or above) an
|
|
1827
|
+
* `ApiConfigProvider`. Returns `undefined` when the client has no base URL,
|
|
1828
|
+
* which is the signal every caller already treats as "cannot build a request".
|
|
1829
|
+
*/
|
|
1830
|
+
function apiBaseOf(client) {
|
|
1831
|
+
if (!client?.baseUrl) return void 0;
|
|
1832
|
+
return client.baseUrl.replace(/\/+$/, "") + (client.apiPath || "/api");
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Provide API configuration (apiUrl, apiPath, getAuthToken) to the entire subtree.
|
|
1836
|
+
* Typically rendered inside `<Rebase>` or at the app root.
|
|
1837
|
+
*/
|
|
1838
|
+
function ApiConfigProvider({ apiUrl, apiPath = DEFAULT_API_PATH, getAuthToken, children }) {
|
|
1839
|
+
const value = React.useMemo(() => ({
|
|
1840
|
+
apiUrl,
|
|
1841
|
+
apiPath,
|
|
1842
|
+
getAuthToken
|
|
1843
|
+
}), [
|
|
1844
|
+
apiUrl,
|
|
1845
|
+
apiPath,
|
|
1846
|
+
getAuthToken
|
|
1847
|
+
]);
|
|
1848
|
+
return /* @__PURE__ */ jsx(ApiConfigContext.Provider, {
|
|
1849
|
+
value,
|
|
1850
|
+
children
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
//#endregion
|
|
1754
1854
|
//#region src/hooks/useBackendStorageSource.ts
|
|
1755
1855
|
/**
|
|
1756
1856
|
* React hook for using backend storage API as a StorageSource
|
|
@@ -1770,8 +1870,8 @@ function useRebaseRegistryDispatch() {
|
|
|
1770
1870
|
* <Rebase storageSource={storageSource} ... />
|
|
1771
1871
|
* ```
|
|
1772
1872
|
*/
|
|
1773
|
-
function useBackendStorageSource({ apiUrl, getAuthToken }) {
|
|
1774
|
-
const storageBasePath = `${apiUrl}/
|
|
1873
|
+
function useBackendStorageSource({ apiUrl, apiPath = DEFAULT_API_PATH, getAuthToken }) {
|
|
1874
|
+
const storageBasePath = `${apiUrl.replace(/\/+$/, "")}${apiPath}/storage`;
|
|
1775
1875
|
const urlsCache = useMemo(() => /* @__PURE__ */ new Map(), []);
|
|
1776
1876
|
/**
|
|
1777
1877
|
* Make an authenticated request to the storage API
|
|
@@ -1933,30 +2033,6 @@ function usePermissions() {
|
|
|
1933
2033
|
]);
|
|
1934
2034
|
}
|
|
1935
2035
|
//#endregion
|
|
1936
|
-
//#region src/hooks/ApiConfigContext.tsx
|
|
1937
|
-
var ApiConfigContext = React.createContext(void 0);
|
|
1938
|
-
/**
|
|
1939
|
-
* Read the API config from context. Returns `undefined` if no provider is present,
|
|
1940
|
-
* allowing hooks to fall back to their own props.
|
|
1941
|
-
*/
|
|
1942
|
-
function useApiConfig() {
|
|
1943
|
-
return useContext(ApiConfigContext);
|
|
1944
|
-
}
|
|
1945
|
-
/**
|
|
1946
|
-
* Provide API configuration (apiUrl, getAuthToken) to the entire subtree.
|
|
1947
|
-
* Typically rendered inside `<Rebase>` or at the app root.
|
|
1948
|
-
*/
|
|
1949
|
-
function ApiConfigProvider({ apiUrl, getAuthToken, children }) {
|
|
1950
|
-
const value = React.useMemo(() => ({
|
|
1951
|
-
apiUrl,
|
|
1952
|
-
getAuthToken
|
|
1953
|
-
}), [apiUrl, getAuthToken]);
|
|
1954
|
-
return /* @__PURE__ */ jsx(ApiConfigContext.Provider, {
|
|
1955
|
-
value,
|
|
1956
|
-
children
|
|
1957
|
-
});
|
|
1958
|
-
}
|
|
1959
|
-
//#endregion
|
|
1960
2036
|
//#region src/hooks/useTranslation.ts
|
|
1961
2037
|
var REBASE_NS$1 = "rebase_core";
|
|
1962
2038
|
/**
|
|
@@ -6318,7 +6394,7 @@ function KanbanBoardDemo() {
|
|
|
6318
6394
|
const [columns, setColumns] = useState(STATUS_COLUMNS);
|
|
6319
6395
|
const assignColumn = useCallback((item) => item.data.status, []);
|
|
6320
6396
|
const handleItemsReorder = useCallback((items, moveInfo) => {
|
|
6321
|
-
|
|
6397
|
+
const updatedItems = items.map((item) => {
|
|
6322
6398
|
if (moveInfo && item.id === moveInfo.itemId && moveInfo.sourceColumn !== moveInfo.targetColumn) return {
|
|
6323
6399
|
...item,
|
|
6324
6400
|
data: {
|
|
@@ -6328,7 +6404,8 @@ function KanbanBoardDemo() {
|
|
|
6328
6404
|
}
|
|
6329
6405
|
};
|
|
6330
6406
|
return item;
|
|
6331
|
-
})
|
|
6407
|
+
});
|
|
6408
|
+
setBoardData(updatedItems);
|
|
6332
6409
|
}, []);
|
|
6333
6410
|
const handleColumnReorder = useCallback((reordered) => setColumns(reordered), []);
|
|
6334
6411
|
const columnLoadingState = useMemo(() => {
|
|
@@ -7563,6 +7640,22 @@ function UIReferenceView() {
|
|
|
7563
7640
|
disabled: true,
|
|
7564
7641
|
value: "Read only",
|
|
7565
7642
|
onChange: () => {}
|
|
7643
|
+
}),
|
|
7644
|
+
/* @__PURE__ */ jsx(TextField, {
|
|
7645
|
+
size: "medium",
|
|
7646
|
+
label: "Medium",
|
|
7647
|
+
placeholder: "Placeholder under the label"
|
|
7648
|
+
}),
|
|
7649
|
+
/* @__PURE__ */ jsx(TextField, {
|
|
7650
|
+
size: "small",
|
|
7651
|
+
label: "Small",
|
|
7652
|
+
placeholder: "Placeholder under the label"
|
|
7653
|
+
}),
|
|
7654
|
+
/* @__PURE__ */ jsx(TextField, {
|
|
7655
|
+
size: "smallest",
|
|
7656
|
+
label: "Smallest",
|
|
7657
|
+
value: "Filled value",
|
|
7658
|
+
onChange: () => {}
|
|
7566
7659
|
})
|
|
7567
7660
|
]
|
|
7568
7661
|
})]
|
|
@@ -8012,7 +8105,7 @@ function UIReferenceView() {
|
|
|
8012
8105
|
/* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx("div", {
|
|
8013
8106
|
className: "flex flex-wrap gap-2",
|
|
8014
8107
|
children: user.roles.map((role) => /* @__PURE__ */ jsx(Chip, {
|
|
8015
|
-
colorScheme: role.isAdmin ? "
|
|
8108
|
+
colorScheme: role.isAdmin ? "purple" : "blue",
|
|
8016
8109
|
size: "small",
|
|
8017
8110
|
children: role.name
|
|
8018
8111
|
}, role.id))
|
|
@@ -8336,8 +8429,10 @@ function UserSettingsView() {
|
|
|
8336
8429
|
setLoadingSessions(true);
|
|
8337
8430
|
setSessionsError(null);
|
|
8338
8431
|
try {
|
|
8339
|
-
if (authController.fetchSessions)
|
|
8340
|
-
|
|
8432
|
+
if (authController.fetchSessions) {
|
|
8433
|
+
const sortedSessions = (await authController.fetchSessions() || []).sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
|
|
8434
|
+
setSessions(sortedSessions);
|
|
8435
|
+
} else throw new Error("fetchSessions not implemented in this auth controller.");
|
|
8341
8436
|
} catch (e) {
|
|
8342
8437
|
setSessionsError(e instanceof Error ? e.message : String(e));
|
|
8343
8438
|
} finally {
|
|
@@ -9723,6 +9818,7 @@ var en = {
|
|
|
9723
9818
|
log_out: "Log out",
|
|
9724
9819
|
column_cannot_be_edited: "This column can't be edited directly",
|
|
9725
9820
|
close: "Close",
|
|
9821
|
+
hide_list: "Hide list",
|
|
9726
9822
|
unsaved_local_changes: "Unsaved Local changes",
|
|
9727
9823
|
unsaved_local_changes_description: "This document was edited locally and has unsaved changes. These local changes will be lost if you don't apply them.",
|
|
9728
9824
|
preview_changes: "Preview Changes",
|
|
@@ -10527,7 +10623,22 @@ var en = {
|
|
|
10527
10623
|
datetime_automatic_value: "Automatic value",
|
|
10528
10624
|
markdown_paste_behavior: "Paste behavior",
|
|
10529
10625
|
markdown_strip_html: "Strip HTML on paste",
|
|
10530
|
-
markdown_convert_pasted: "Convert pasted text to markdown"
|
|
10626
|
+
markdown_convert_pasted: "Convert pasted text to markdown",
|
|
10627
|
+
entity_saved: "Saved",
|
|
10628
|
+
more_actions: "More actions",
|
|
10629
|
+
record_history: "History",
|
|
10630
|
+
inspect_record: "Inspect record",
|
|
10631
|
+
inspect: "Inspect",
|
|
10632
|
+
close_inspector: "Close inspector",
|
|
10633
|
+
history_revert: "Revert to this version",
|
|
10634
|
+
history_revert_title: "Revert data to this version?",
|
|
10635
|
+
history_reverted: "Reverted to selected version",
|
|
10636
|
+
history_revert_error: "Error reverting entity",
|
|
10637
|
+
history_revert_dirty: "Please save or discard your changes before reverting",
|
|
10638
|
+
history_empty: "No history available",
|
|
10639
|
+
history_empty_description: "When you save a record, a new version is created and stored in the history.",
|
|
10640
|
+
history_new_entity: "History is only available for existing records",
|
|
10641
|
+
history_no_more: "No more history"
|
|
10531
10642
|
};
|
|
10532
10643
|
//#endregion
|
|
10533
10644
|
//#region src/locales/es.ts
|
|
@@ -10604,6 +10715,7 @@ var es = {
|
|
|
10604
10715
|
log_out: "Cerrar sesión",
|
|
10605
10716
|
column_cannot_be_edited: "Esta columna no se puede editar directamente",
|
|
10606
10717
|
close: "Cerrar",
|
|
10718
|
+
hide_list: "Ocultar lista",
|
|
10607
10719
|
unsaved_local_changes: "Cambios locales sin guardar",
|
|
10608
10720
|
unsaved_local_changes_description: "Este documento ha sido editado localmente y tiene cambios sin guardar. Estos cambios locales se perderán si no los aplicas.",
|
|
10609
10721
|
preview_changes: "Previsualizar cambios",
|
|
@@ -11373,7 +11485,22 @@ var es = {
|
|
|
11373
11485
|
datetime_automatic_value: "Valor automático",
|
|
11374
11486
|
markdown_paste_behavior: "Comportamiento al pegar",
|
|
11375
11487
|
markdown_strip_html: "Eliminar HTML al pegar",
|
|
11376
|
-
markdown_convert_pasted: "Convertir texto pegado a markdown"
|
|
11488
|
+
markdown_convert_pasted: "Convertir texto pegado a markdown",
|
|
11489
|
+
entity_saved: "Guardado",
|
|
11490
|
+
more_actions: "Más acciones",
|
|
11491
|
+
record_history: "Historial",
|
|
11492
|
+
inspect_record: "Inspeccionar registro",
|
|
11493
|
+
inspect: "Inspeccionar",
|
|
11494
|
+
close_inspector: "Cerrar el inspector",
|
|
11495
|
+
history_revert: "Volver a esta versión",
|
|
11496
|
+
history_revert_title: "¿Volver a esta versión de los datos?",
|
|
11497
|
+
history_reverted: "Se volvió a la versión seleccionada",
|
|
11498
|
+
history_revert_error: "Error al revertir el registro",
|
|
11499
|
+
history_revert_dirty: "Guarda o descarta tus cambios antes de revertir",
|
|
11500
|
+
history_empty: "No hay historial disponible",
|
|
11501
|
+
history_empty_description: "Al guardar un registro se crea una nueva versión y se almacena en el historial.",
|
|
11502
|
+
history_new_entity: "El historial solo está disponible para registros existentes",
|
|
11503
|
+
history_no_more: "No hay más historial"
|
|
11377
11504
|
};
|
|
11378
11505
|
//#endregion
|
|
11379
11506
|
//#region src/locales/de.ts
|
|
@@ -11442,6 +11569,7 @@ var de = {
|
|
|
11442
11569
|
log_out: "Abmelden",
|
|
11443
11570
|
column_cannot_be_edited: "Diese Spalte kann nicht direkt bearbeitet werden",
|
|
11444
11571
|
close: "Schließen",
|
|
11572
|
+
hide_list: "Liste ausblenden",
|
|
11445
11573
|
unsaved_local_changes: "Ungespeicherte lokale Änderungen",
|
|
11446
11574
|
unsaved_local_changes_description: "Dieses Dokument wurde lokal bearbeitet und weist ungespeicherte Änderungen auf. Diese lokalen Änderungen gehen verloren, wenn Sie sie nicht anwenden.",
|
|
11447
11575
|
preview_changes: "Änderungen in der Vorschau anzeigen",
|
|
@@ -12201,7 +12329,22 @@ var de = {
|
|
|
12201
12329
|
datetime_automatic_value: "Automatischer Wert",
|
|
12202
12330
|
markdown_paste_behavior: "Einfügeverhalten",
|
|
12203
12331
|
markdown_strip_html: "HTML beim Einfügen entfernen",
|
|
12204
|
-
markdown_convert_pasted: "Eingefügten Text in Markdown umwandeln"
|
|
12332
|
+
markdown_convert_pasted: "Eingefügten Text in Markdown umwandeln",
|
|
12333
|
+
entity_saved: "Gespeichert",
|
|
12334
|
+
more_actions: "Weitere Aktionen",
|
|
12335
|
+
record_history: "Verlauf",
|
|
12336
|
+
inspect_record: "Datensatz inspizieren",
|
|
12337
|
+
inspect: "Inspizieren",
|
|
12338
|
+
close_inspector: "Inspektor schließen",
|
|
12339
|
+
history_revert: "Auf diese Version zurücksetzen",
|
|
12340
|
+
history_revert_title: "Daten auf diese Version zurücksetzen?",
|
|
12341
|
+
history_reverted: "Auf die gewählte Version zurückgesetzt",
|
|
12342
|
+
history_revert_error: "Fehler beim Zurücksetzen des Datensatzes",
|
|
12343
|
+
history_revert_dirty: "Bitte speichere oder verwirf deine Änderungen vor dem Zurücksetzen",
|
|
12344
|
+
history_empty: "Kein Verlauf vorhanden",
|
|
12345
|
+
history_empty_description: "Beim Speichern eines Datensatzes wird eine neue Version erstellt und im Verlauf abgelegt.",
|
|
12346
|
+
history_new_entity: "Der Verlauf ist nur für vorhandene Datensätze verfügbar",
|
|
12347
|
+
history_no_more: "Kein weiterer Verlauf"
|
|
12205
12348
|
};
|
|
12206
12349
|
//#endregion
|
|
12207
12350
|
//#region src/locales/fr.ts
|
|
@@ -12270,6 +12413,7 @@ var fr = {
|
|
|
12270
12413
|
log_out: "Se déconnecter",
|
|
12271
12414
|
column_cannot_be_edited: "Cette colonne ne peut pas être modifiée directement",
|
|
12272
12415
|
close: "Fermer",
|
|
12416
|
+
hide_list: "Masquer la liste",
|
|
12273
12417
|
unsaved_local_changes: "Modifications locales non enregistrées",
|
|
12274
12418
|
unsaved_local_changes_description: "Ce document a été modifié localement et contient des modifications non enregistrées. Ces modifications locales seront perdues si vous ne les appliquez pas.",
|
|
12275
12419
|
preview_changes: "Aperçu des modifications",
|
|
@@ -13029,7 +13173,22 @@ var fr = {
|
|
|
13029
13173
|
datetime_automatic_value: "Valeur automatique",
|
|
13030
13174
|
markdown_paste_behavior: "Comportement au collage",
|
|
13031
13175
|
markdown_strip_html: "Supprimer le HTML au collage",
|
|
13032
|
-
markdown_convert_pasted: "Convertir le texte collé en markdown"
|
|
13176
|
+
markdown_convert_pasted: "Convertir le texte collé en markdown",
|
|
13177
|
+
entity_saved: "Enregistré",
|
|
13178
|
+
more_actions: "Plus d'actions",
|
|
13179
|
+
record_history: "Historique",
|
|
13180
|
+
inspect_record: "Inspecter l'enregistrement",
|
|
13181
|
+
inspect: "Inspecter",
|
|
13182
|
+
close_inspector: "Fermer l'inspecteur",
|
|
13183
|
+
history_revert: "Revenir à cette version",
|
|
13184
|
+
history_revert_title: "Revenir à cette version des données ?",
|
|
13185
|
+
history_reverted: "Retour à la version sélectionnée",
|
|
13186
|
+
history_revert_error: "Erreur lors du retour en arrière",
|
|
13187
|
+
history_revert_dirty: "Enregistrez ou annulez vos modifications avant de revenir en arrière",
|
|
13188
|
+
history_empty: "Aucun historique disponible",
|
|
13189
|
+
history_empty_description: "À chaque enregistrement, une nouvelle version est créée et conservée dans l'historique.",
|
|
13190
|
+
history_new_entity: "L'historique n'est disponible que pour les enregistrements existants",
|
|
13191
|
+
history_no_more: "Plus d'historique"
|
|
13033
13192
|
};
|
|
13034
13193
|
//#endregion
|
|
13035
13194
|
//#region src/locales/it.ts
|
|
@@ -13098,6 +13257,7 @@ var it = {
|
|
|
13098
13257
|
log_out: "Esci",
|
|
13099
13258
|
column_cannot_be_edited: "Questa colonna non può essere modificata direttamente",
|
|
13100
13259
|
close: "Chiudi",
|
|
13260
|
+
hide_list: "Nascondi elenco",
|
|
13101
13261
|
unsaved_local_changes: "Modifiche locali non salvate",
|
|
13102
13262
|
unsaved_local_changes_description: "Questo documento è stato modificato localmente e ha modifiche non salvate. Queste modifiche locali andranno perse se non le applichi.",
|
|
13103
13263
|
preview_changes: "Anteprima modifiche",
|
|
@@ -13857,7 +14017,22 @@ var it = {
|
|
|
13857
14017
|
datetime_automatic_value: "Valore automatico",
|
|
13858
14018
|
markdown_paste_behavior: "Comportamento incolla",
|
|
13859
14019
|
markdown_strip_html: "Rimuovi HTML all'incolla",
|
|
13860
|
-
markdown_convert_pasted: "Converti testo incollato in markdown"
|
|
14020
|
+
markdown_convert_pasted: "Converti testo incollato in markdown",
|
|
14021
|
+
entity_saved: "Salvato",
|
|
14022
|
+
more_actions: "Altre azioni",
|
|
14023
|
+
record_history: "Cronologia",
|
|
14024
|
+
inspect_record: "Ispeziona record",
|
|
14025
|
+
inspect: "Ispeziona",
|
|
14026
|
+
close_inspector: "Chiudi l'ispettore",
|
|
14027
|
+
history_revert: "Torna a questa versione",
|
|
14028
|
+
history_revert_title: "Ripristinare i dati a questa versione?",
|
|
14029
|
+
history_reverted: "Ripristinata la versione selezionata",
|
|
14030
|
+
history_revert_error: "Errore durante il ripristino del record",
|
|
14031
|
+
history_revert_dirty: "Salva o annulla le modifiche prima di ripristinare",
|
|
14032
|
+
history_empty: "Nessuna cronologia disponibile",
|
|
14033
|
+
history_empty_description: "Quando salvi un record viene creata una nuova versione e conservata nella cronologia.",
|
|
14034
|
+
history_new_entity: "La cronologia è disponibile solo per i record esistenti",
|
|
14035
|
+
history_no_more: "Nessun'altra cronologia"
|
|
13861
14036
|
};
|
|
13862
14037
|
//#endregion
|
|
13863
14038
|
//#region src/locales/hi.ts
|
|
@@ -13926,6 +14101,7 @@ var hi = {
|
|
|
13926
14101
|
log_out: "लॉग आउट",
|
|
13927
14102
|
column_cannot_be_edited: "इस कॉलम को सीधे संपादित नहीं किया जा सकता",
|
|
13928
14103
|
close: "बंद करें",
|
|
14104
|
+
hide_list: "सूची छिपाएँ",
|
|
13929
14105
|
unsaved_local_changes: "सहेजे नहीं गए स्थानीय परिवर्तन",
|
|
13930
14106
|
unsaved_local_changes_description: "इस दस्तावेज़ को स्थानीय स्तर पर संपादित किया गया था और इसमें सहेजे नहीं गए परिवर्तन हैं। यदि आप इन्हें लागू नहीं करते हैं तो ये स्थानीय परिवर्तन खो जाएंगे।",
|
|
13931
14107
|
preview_changes: "परिवर्तनों का पूर्वावलोकन करें",
|
|
@@ -14685,7 +14861,22 @@ var hi = {
|
|
|
14685
14861
|
datetime_automatic_value: "स्वचालित मान",
|
|
14686
14862
|
markdown_paste_behavior: "पेस्ट व्यवहार",
|
|
14687
14863
|
markdown_strip_html: "पेस्ट करते समय HTML हटाएं",
|
|
14688
|
-
markdown_convert_pasted: "पेस्ट किए गए टेक्स्ट को मार्कडाउन में बदलें"
|
|
14864
|
+
markdown_convert_pasted: "पेस्ट किए गए टेक्स्ट को मार्कडाउन में बदलें",
|
|
14865
|
+
entity_saved: "सहेजा गया",
|
|
14866
|
+
more_actions: "अधिक क्रियाएँ",
|
|
14867
|
+
record_history: "इतिहास",
|
|
14868
|
+
inspect_record: "रिकॉर्ड जाँचें",
|
|
14869
|
+
inspect: "जाँचें",
|
|
14870
|
+
close_inspector: "इंस्पेक्टर बंद करें",
|
|
14871
|
+
history_revert: "इस संस्करण पर लौटें",
|
|
14872
|
+
history_revert_title: "डेटा को इस संस्करण पर लौटाएँ?",
|
|
14873
|
+
history_reverted: "चयनित संस्करण पर लौटा दिया गया",
|
|
14874
|
+
history_revert_error: "रिकॉर्ड लौटाने में त्रुटि",
|
|
14875
|
+
history_revert_dirty: "लौटाने से पहले अपने बदलाव सहेजें या रद्द करें",
|
|
14876
|
+
history_empty: "कोई इतिहास उपलब्ध नहीं",
|
|
14877
|
+
history_empty_description: "रिकॉर्ड सहेजने पर एक नया संस्करण बनता है और इतिहास में रखा जाता है।",
|
|
14878
|
+
history_new_entity: "इतिहास केवल मौजूदा रिकॉर्ड के लिए उपलब्ध है",
|
|
14879
|
+
history_no_more: "और इतिहास नहीं"
|
|
14689
14880
|
};
|
|
14690
14881
|
//#endregion
|
|
14691
14882
|
//#region src/locales/pt.ts
|
|
@@ -14759,6 +14950,7 @@ var pt = {
|
|
|
14759
14950
|
log_out: "Terminar sessão",
|
|
14760
14951
|
column_cannot_be_edited: "Esta coluna não pode ser editada diretamente",
|
|
14761
14952
|
close: "Fechar",
|
|
14953
|
+
hide_list: "Ocultar lista",
|
|
14762
14954
|
unsaved_local_changes: "Alterações locais não guardadas",
|
|
14763
14955
|
unsaved_local_changes_description: "Este documento foi editado localmente e tem alterações não guardadas. Estas alterações locais serão perdidas se não as aplicar.",
|
|
14764
14956
|
preview_changes: "Pré-visualizar alterações",
|
|
@@ -15518,7 +15710,22 @@ var pt = {
|
|
|
15518
15710
|
datetime_automatic_value: "Valor automático",
|
|
15519
15711
|
markdown_paste_behavior: "Comportamento ao colar",
|
|
15520
15712
|
markdown_strip_html: "Remover HTML ao colar",
|
|
15521
|
-
markdown_convert_pasted: "Converter texto colado para markdown"
|
|
15713
|
+
markdown_convert_pasted: "Converter texto colado para markdown",
|
|
15714
|
+
entity_saved: "Guardado",
|
|
15715
|
+
more_actions: "Mais ações",
|
|
15716
|
+
record_history: "Histórico",
|
|
15717
|
+
inspect_record: "Inspecionar registo",
|
|
15718
|
+
inspect: "Inspecionar",
|
|
15719
|
+
close_inspector: "Fechar o inspetor",
|
|
15720
|
+
history_revert: "Voltar a esta versão",
|
|
15721
|
+
history_revert_title: "Reverter os dados para esta versão?",
|
|
15722
|
+
history_reverted: "Revertido para a versão selecionada",
|
|
15723
|
+
history_revert_error: "Erro ao reverter o registo",
|
|
15724
|
+
history_revert_dirty: "Guarde ou descarte as suas alterações antes de reverter",
|
|
15725
|
+
history_empty: "Nenhum histórico disponível",
|
|
15726
|
+
history_empty_description: "Ao guardar um registo é criada uma nova versão, guardada no histórico.",
|
|
15727
|
+
history_new_entity: "O histórico só está disponível para registos existentes",
|
|
15728
|
+
history_no_more: "Sem mais histórico"
|
|
15522
15729
|
};
|
|
15523
15730
|
//#endregion
|
|
15524
15731
|
//#region src/i18n/RebaseI18nProvider.tsx
|
|
@@ -15852,6 +16059,7 @@ function Rebase(props) {
|
|
|
15852
16059
|
const resolvedApiUrl = apiUrl || client?.baseUrl || (typeof window !== "undefined" ? window.location.origin : "");
|
|
15853
16060
|
if (resolvedApiUrl) return /* @__PURE__ */ jsx(ApiConfigProvider, {
|
|
15854
16061
|
apiUrl: resolvedApiUrl,
|
|
16062
|
+
apiPath: client?.apiPath,
|
|
15855
16063
|
getAuthToken: authController.getAuthToken,
|
|
15856
16064
|
children: content
|
|
15857
16065
|
});
|
|
@@ -15998,7 +16206,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
15998
16206
|
try {
|
|
15999
16207
|
await auth.signOut();
|
|
16000
16208
|
} catch (error) {
|
|
16001
|
-
|
|
16209
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16210
|
+
setAuthProviderError(err);
|
|
16002
16211
|
} finally {
|
|
16003
16212
|
setAuthLoading(false);
|
|
16004
16213
|
}
|
|
@@ -16010,7 +16219,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16010
16219
|
try {
|
|
16011
16220
|
await auth.signInWithEmail(email, password);
|
|
16012
16221
|
} catch (error) {
|
|
16013
|
-
|
|
16222
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16223
|
+
setAuthProviderError(err);
|
|
16014
16224
|
throw error;
|
|
16015
16225
|
} finally {
|
|
16016
16226
|
setAuthLoading(false);
|
|
@@ -16023,7 +16233,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16023
16233
|
try {
|
|
16024
16234
|
await auth.signUp(email, password, displayName);
|
|
16025
16235
|
} catch (error) {
|
|
16026
|
-
|
|
16236
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16237
|
+
setAuthProviderError(err);
|
|
16027
16238
|
throw error;
|
|
16028
16239
|
} finally {
|
|
16029
16240
|
setAuthLoading(false);
|
|
@@ -16036,7 +16247,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16036
16247
|
try {
|
|
16037
16248
|
await auth.signInWithGoogle(payload);
|
|
16038
16249
|
} catch (error) {
|
|
16039
|
-
|
|
16250
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16251
|
+
setAuthProviderError(err);
|
|
16040
16252
|
throw error;
|
|
16041
16253
|
} finally {
|
|
16042
16254
|
setAuthLoading(false);
|
|
@@ -16049,7 +16261,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16049
16261
|
try {
|
|
16050
16262
|
await auth.signInWithOAuth(providerId, payload);
|
|
16051
16263
|
} catch (error) {
|
|
16052
|
-
|
|
16264
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16265
|
+
setAuthProviderError(err);
|
|
16053
16266
|
throw error;
|
|
16054
16267
|
} finally {
|
|
16055
16268
|
setAuthLoading(false);
|
|
@@ -16066,7 +16279,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16066
16279
|
try {
|
|
16067
16280
|
await auth.resetPasswordForEmail(email);
|
|
16068
16281
|
} catch (error) {
|
|
16069
|
-
|
|
16282
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16283
|
+
setAuthProviderError(err);
|
|
16070
16284
|
throw error;
|
|
16071
16285
|
} finally {
|
|
16072
16286
|
setAuthLoading(false);
|
|
@@ -16079,7 +16293,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16079
16293
|
try {
|
|
16080
16294
|
await auth.resetPassword(token, password);
|
|
16081
16295
|
} catch (error) {
|
|
16082
|
-
|
|
16296
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16297
|
+
setAuthProviderError(err);
|
|
16083
16298
|
throw error;
|
|
16084
16299
|
} finally {
|
|
16085
16300
|
setAuthLoading(false);
|
|
@@ -16093,7 +16308,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16093
16308
|
await auth.changePassword(oldPassword, newPassword);
|
|
16094
16309
|
await auth.signOut();
|
|
16095
16310
|
} catch (error) {
|
|
16096
|
-
|
|
16311
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16312
|
+
setAuthProviderError(err);
|
|
16097
16313
|
throw error;
|
|
16098
16314
|
} finally {
|
|
16099
16315
|
setAuthLoading(false);
|
|
@@ -16109,7 +16325,8 @@ function useRebaseAuthController(props = {}) {
|
|
|
16109
16325
|
photoURL
|
|
16110
16326
|
});
|
|
16111
16327
|
} catch (error) {
|
|
16112
|
-
|
|
16328
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16329
|
+
setAuthProviderError(err);
|
|
16113
16330
|
throw error;
|
|
16114
16331
|
} finally {
|
|
16115
16332
|
setAuthLoading(false);
|
|
@@ -16180,12 +16397,6 @@ function useRebaseAuthController(props = {}) {
|
|
|
16180
16397
|
* here is the unauthenticated `/api/auth/config` probe used to detect
|
|
16181
16398
|
* bootstrap mode and enabled providers before a session exists.
|
|
16182
16399
|
*/
|
|
16183
|
-
/**
|
|
16184
|
-
* @deprecated Use {@link RebaseApiError} (from `@rebasepro/types`, re-exported by
|
|
16185
|
-
* `@rebasepro/client`). Kept as an alias so `instanceof` / imports keep working;
|
|
16186
|
-
* errors thrown here now carry `.code` and `.status` on the unified type.
|
|
16187
|
-
*/
|
|
16188
|
-
var AuthApiError = RebaseApiError;
|
|
16189
16400
|
async function handleResponse(response) {
|
|
16190
16401
|
let data;
|
|
16191
16402
|
try {
|
|
@@ -16238,11 +16449,11 @@ function createAuthConfigCache() {
|
|
|
16238
16449
|
* Concurrent calls are deduplicated: only one network request is made
|
|
16239
16450
|
* and all callers share the same promise.
|
|
16240
16451
|
*/
|
|
16241
|
-
async function fetchAuthConfig(apiUrl, cache) {
|
|
16452
|
+
async function fetchAuthConfig(apiUrl, cache, apiPath = DEFAULT_API_PATH) {
|
|
16242
16453
|
if (cache.cached) return cache.cached;
|
|
16243
16454
|
if (cache.inflight) return cache.inflight;
|
|
16244
16455
|
cache.inflight = (async () => {
|
|
16245
|
-
return handleResponse(await fetchWithHandling(`${apiUrl}/
|
|
16456
|
+
return handleResponse(await fetchWithHandling(`${apiUrl.replace(/\/+$/, "")}${apiPath}/auth/config`, {
|
|
16246
16457
|
method: "GET",
|
|
16247
16458
|
headers: { "Content-Type": "application/json" }
|
|
16248
16459
|
}));
|
|
@@ -16568,7 +16779,7 @@ function useStorageUploadController({ entityId, entityValues, path, value, prope
|
|
|
16568
16779
|
if (!storage) throw Error("Storage meta must be specified");
|
|
16569
16780
|
const processFile = storage?.processFile;
|
|
16570
16781
|
const metadata = storage?.metadata;
|
|
16571
|
-
const size =
|
|
16782
|
+
const size = "medium";
|
|
16572
16783
|
const imageResize = storage?.imageResize;
|
|
16573
16784
|
const internalInitialValue = getInternalInitialValue(multipleFilesSupported, value, metadata, size);
|
|
16574
16785
|
const [initialValue, setInitialValue] = useState(value);
|
|
@@ -16660,7 +16871,8 @@ function useStorageUploadController({ entityId, entityValues, path, value, prope
|
|
|
16660
16871
|
]),
|
|
16661
16872
|
onFileUploadError: useCallback((entry) => {
|
|
16662
16873
|
console.debug("onFileUploadError", entry);
|
|
16663
|
-
|
|
16874
|
+
const newValue = internalValue.filter((item) => item.id !== entry.id);
|
|
16875
|
+
setInternalValue(newValue);
|
|
16664
16876
|
}, [internalValue]),
|
|
16665
16877
|
onFilesAdded: useCallback(async (acceptedFiles) => {
|
|
16666
16878
|
if (!acceptedFiles.length || disabled) return;
|
|
@@ -16775,7 +16987,7 @@ function getColorScheme(enumValues, key) {
|
|
|
16775
16987
|
const labelOrConfig = getLabelOrConfigFrom(enumValues, key);
|
|
16776
16988
|
if (!labelOrConfig?.color) return getColorSchemeForSeed(key.toString());
|
|
16777
16989
|
if (typeof labelOrConfig === "object" && "color" in labelOrConfig) {
|
|
16778
|
-
if (typeof labelOrConfig.color === "string") return
|
|
16990
|
+
if (typeof labelOrConfig.color === "string") return getColorSchemeForKey(labelOrConfig.color);
|
|
16779
16991
|
if (typeof labelOrConfig.color === "object") return labelOrConfig.color;
|
|
16780
16992
|
}
|
|
16781
16993
|
}
|
|
@@ -16809,9 +17021,21 @@ var STUDIO_NAVIGATION_GROUPS = [
|
|
|
16809
17021
|
*/
|
|
16810
17022
|
var CONTAINER_FULL_WIDTH = "100vw";
|
|
16811
17023
|
/** @internal See {@link CONTAINER_FULL_WIDTH}. */
|
|
16812
|
-
var ADDITIONAL_TAB_WIDTH = "55vw";
|
|
16813
|
-
/** @internal See {@link CONTAINER_FULL_WIDTH}. */
|
|
16814
17024
|
var FORM_CONTAINER_WIDTH = "768px";
|
|
17025
|
+
/**
|
|
17026
|
+
* How wide the side panel opens when neither the caller nor the collection
|
|
17027
|
+
* says otherwise.
|
|
17028
|
+
*
|
|
17029
|
+
* Sized from what it has to hold rather than from a round number: the form's
|
|
17030
|
+
* content column plus its metadata rail plus gutters, which is also the width
|
|
17031
|
+
* at which the form stops being a single stack and picks up the same
|
|
17032
|
+
* two-column layout it has in full screen. Capped against the viewport so a
|
|
17033
|
+
* panel never becomes the whole window on a laptop — at that point you want
|
|
17034
|
+
* full screen, and there is a button for it.
|
|
17035
|
+
*
|
|
17036
|
+
* @internal See {@link CONTAINER_FULL_WIDTH}.
|
|
17037
|
+
*/
|
|
17038
|
+
var SIDE_PANEL_DEFAULT_WIDTH = "min(1160px, 88vw)";
|
|
16815
17039
|
//#endregion
|
|
16816
17040
|
//#region src/internal/useRestoreScroll.tsx
|
|
16817
17041
|
var scrollsMap = {};
|
|
@@ -16935,7 +17159,8 @@ var NOOP_BRIDGE = {
|
|
|
16935
17159
|
breadcrumbs: [],
|
|
16936
17160
|
set: () => {},
|
|
16937
17161
|
updateCount: () => {}
|
|
16938
|
-
}
|
|
17162
|
+
},
|
|
17163
|
+
capabilities: { codebase: true }
|
|
16939
17164
|
};
|
|
16940
17165
|
var StudioBridgeContext = createContext(NOOP_BRIDGE);
|
|
16941
17166
|
/**
|
|
@@ -16959,7 +17184,14 @@ function StudioBridgeProvider({ value, children }) {
|
|
|
16959
17184
|
const merged = React.useMemo(() => ({
|
|
16960
17185
|
...NOOP_BRIDGE,
|
|
16961
17186
|
...value
|
|
16962
|
-
}), [
|
|
17187
|
+
}), [
|
|
17188
|
+
value.collectionRegistry,
|
|
17189
|
+
value.sidePanelController,
|
|
17190
|
+
value.urlController,
|
|
17191
|
+
value.navigationState,
|
|
17192
|
+
value.breadcrumbs,
|
|
17193
|
+
value.capabilities
|
|
17194
|
+
]);
|
|
16963
17195
|
return /* @__PURE__ */ jsx(StudioBridgeContext.Provider, {
|
|
16964
17196
|
value: merged,
|
|
16965
17197
|
children
|
|
@@ -16985,6 +17217,10 @@ function useStudioNavigationState() {
|
|
|
16985
17217
|
function useStudioBreadcrumbs() {
|
|
16986
17218
|
return useContext(StudioBridgeContext).breadcrumbs;
|
|
16987
17219
|
}
|
|
17220
|
+
/** What the host can do — see {@link StudioCapabilities}. */
|
|
17221
|
+
function useStudioCapabilities() {
|
|
17222
|
+
return useContext(StudioBridgeContext).capabilities;
|
|
17223
|
+
}
|
|
16988
17224
|
var StudioBridgeRegistryContext = createContext(null);
|
|
16989
17225
|
/**
|
|
16990
17226
|
* Provider that creates a self-assembling bridge.
|
|
@@ -17247,6 +17483,326 @@ function resolveFilterOperators({ property, isArray, engine }) {
|
|
|
17247
17483
|
return typeDefaults.filter((op) => engineOps.has(op) && (narrowingSet === void 0 || narrowingSet.has(op)));
|
|
17248
17484
|
}
|
|
17249
17485
|
//#endregion
|
|
17486
|
+
//#region src/collections/property_presentation.ts
|
|
17487
|
+
function isReadOnly(property) {
|
|
17488
|
+
if (property.admin?.readOnly) return true;
|
|
17489
|
+
if (property.type === "date") {
|
|
17490
|
+
if (property.autoValue) return true;
|
|
17491
|
+
}
|
|
17492
|
+
if (property.type === "reference") return !property.path && !("Field" in (property.admin || {}) && property.admin?.Field);
|
|
17493
|
+
return false;
|
|
17494
|
+
}
|
|
17495
|
+
function isHidden(property) {
|
|
17496
|
+
return typeof property.admin?.disabled === "object" && Boolean(property.admin?.disabled.hidden);
|
|
17497
|
+
}
|
|
17498
|
+
function applyPropertyConditions(property, context) {
|
|
17499
|
+
const { conditions } = property;
|
|
17500
|
+
if (!conditions) return property;
|
|
17501
|
+
const result = { ...property };
|
|
17502
|
+
if (conditions.disabled) {
|
|
17503
|
+
if (evaluateCondition(conditions.disabled, context)) {
|
|
17504
|
+
result.admin = result.admin || {};
|
|
17505
|
+
result.admin.disabled = {
|
|
17506
|
+
clearOnDisabled: conditions.clearOnDisabled ?? false,
|
|
17507
|
+
disabledMessage: conditions.disabledMessage,
|
|
17508
|
+
hidden: false
|
|
17509
|
+
};
|
|
17510
|
+
}
|
|
17511
|
+
}
|
|
17512
|
+
if (conditions.hidden) {
|
|
17513
|
+
if (evaluateCondition(conditions.hidden, context)) {
|
|
17514
|
+
result.admin = result.admin || {};
|
|
17515
|
+
result.admin.disabled = {
|
|
17516
|
+
...typeof result.admin?.disabled === "object" ? result.admin.disabled : {},
|
|
17517
|
+
hidden: true,
|
|
17518
|
+
clearOnDisabled: conditions.clearOnDisabled ?? false
|
|
17519
|
+
};
|
|
17520
|
+
}
|
|
17521
|
+
}
|
|
17522
|
+
if (conditions.readOnly) {
|
|
17523
|
+
if (evaluateCondition(conditions.readOnly, context)) {
|
|
17524
|
+
result.admin = result.admin || {};
|
|
17525
|
+
result.admin.readOnly = true;
|
|
17526
|
+
}
|
|
17527
|
+
}
|
|
17528
|
+
if (conditions.required !== void 0) {
|
|
17529
|
+
const isRequired = evaluateCondition(conditions.required, context);
|
|
17530
|
+
result.validation = {
|
|
17531
|
+
...result.validation,
|
|
17532
|
+
required: isRequired,
|
|
17533
|
+
requiredMessage: conditions.requiredMessage
|
|
17534
|
+
};
|
|
17535
|
+
}
|
|
17536
|
+
if (context.isNew && conditions.defaultValue !== void 0) result.defaultValue = evaluateCondition(conditions.defaultValue, context);
|
|
17537
|
+
if ("enum" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) result.enum = applyEnumConditions(result.enum, conditions, context);
|
|
17538
|
+
if (result.type === "reference") {
|
|
17539
|
+
if (conditions.referencePath) result.path = evaluateCondition(conditions.referencePath, context);
|
|
17540
|
+
if (conditions.referenceFilter) {
|
|
17541
|
+
result.admin = result.admin || {};
|
|
17542
|
+
result.admin.fixedFilter = evaluateCondition(conditions.referenceFilter, context);
|
|
17543
|
+
}
|
|
17544
|
+
}
|
|
17545
|
+
if (result.type === "array") {
|
|
17546
|
+
if (conditions.canAddElements !== void 0) {
|
|
17547
|
+
result.admin = result.admin || {};
|
|
17548
|
+
result.admin.canAddElements = evaluateCondition(conditions.canAddElements, context);
|
|
17549
|
+
}
|
|
17550
|
+
if (conditions.sortable !== void 0) {
|
|
17551
|
+
result.admin = result.admin || {};
|
|
17552
|
+
result.admin.sortable = evaluateCondition(conditions.sortable, context);
|
|
17553
|
+
}
|
|
17554
|
+
}
|
|
17555
|
+
return result;
|
|
17556
|
+
}
|
|
17557
|
+
/**
|
|
17558
|
+
* Convert an object with numeric keys back to an array.
|
|
17559
|
+
* Firestore stores arrays as {"0": "a", "1": "b"} to avoid nested arrays.
|
|
17560
|
+
*/
|
|
17561
|
+
function objectToArray(obj) {
|
|
17562
|
+
if (Array.isArray(obj)) return obj.map(String);
|
|
17563
|
+
if (obj && typeof obj === "object") {
|
|
17564
|
+
const keys = Object.keys(obj);
|
|
17565
|
+
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) return keys.sort((a, b) => Number(a) - Number(b)).map((k) => obj[k]).filter((v) => typeof v === "string" || typeof v === "number").map(String);
|
|
17566
|
+
}
|
|
17567
|
+
return [];
|
|
17568
|
+
}
|
|
17569
|
+
/**
|
|
17570
|
+
* Apply enum-specific conditions to filter and modify enum values.
|
|
17571
|
+
*/
|
|
17572
|
+
function applyEnumConditions(enumValues, conditions, context) {
|
|
17573
|
+
let result = [...enumValues];
|
|
17574
|
+
if (conditions.allowedEnumValues) {
|
|
17575
|
+
const allowedArray = objectToArray(evaluateCondition(conditions.allowedEnumValues, context));
|
|
17576
|
+
if (allowedArray.length > 0) result = result.filter((ev) => allowedArray.includes(String(ev.id)));
|
|
17577
|
+
}
|
|
17578
|
+
if (conditions.excludedEnumValues) {
|
|
17579
|
+
const excludedArray = objectToArray(evaluateCondition(conditions.excludedEnumValues, context));
|
|
17580
|
+
if (excludedArray.length > 0) result = result.filter((ev) => !excludedArray.includes(String(ev.id)));
|
|
17581
|
+
}
|
|
17582
|
+
if (conditions.enumConditions) result = result.map((ev) => {
|
|
17583
|
+
const evConditions = conditions.enumConditions?.[ev.id];
|
|
17584
|
+
if (!evConditions) return ev;
|
|
17585
|
+
if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) return null;
|
|
17586
|
+
if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) return {
|
|
17587
|
+
...ev,
|
|
17588
|
+
disabled: true
|
|
17589
|
+
};
|
|
17590
|
+
return ev;
|
|
17591
|
+
}).filter((ev) => ev !== null);
|
|
17592
|
+
return result;
|
|
17593
|
+
}
|
|
17594
|
+
//#endregion
|
|
17595
|
+
//#region src/collections/form-layout.ts
|
|
17596
|
+
/**
|
|
17597
|
+
* Columns in the form grid.
|
|
17598
|
+
*
|
|
17599
|
+
* A local literal rather than an import of `FORM_GRID_COLUMNS`: everything else
|
|
17600
|
+
* this module takes from `@rebasepro/admin-types` is a *type*, erased at build
|
|
17601
|
+
* time, and a runtime value would make this pure function depend on that
|
|
17602
|
+
* package's built output — which is exactly what broke the dev server, since
|
|
17603
|
+
* `@rebasepro/app` resolves that package to its dist. `satisfies PropertySpan`
|
|
17604
|
+
* keeps the two honest: a full-width field and the column count are the same
|
|
17605
|
+
* number by definition.
|
|
17606
|
+
*/
|
|
17607
|
+
var GRID_COLUMNS = 4;
|
|
17608
|
+
/** Does this property's editor need the full width of the column? */
|
|
17609
|
+
function needsFullWidth(property) {
|
|
17610
|
+
switch (property.type) {
|
|
17611
|
+
case "map":
|
|
17612
|
+
case "binary":
|
|
17613
|
+
case "vector": return true;
|
|
17614
|
+
case "array": {
|
|
17615
|
+
if (property.oneOf) return true;
|
|
17616
|
+
const of = Array.isArray(property.of) ? void 0 : property.of;
|
|
17617
|
+
if (!of) return true;
|
|
17618
|
+
if (of.type !== "string" && of.type !== "number") return true;
|
|
17619
|
+
if (of.type === "string" && (of.storage || of.admin?.markdown || of.admin?.multiline)) return true;
|
|
17620
|
+
return false;
|
|
17621
|
+
}
|
|
17622
|
+
case "string": return Boolean(property.storage || property.admin?.markdown || property.admin?.multiline);
|
|
17623
|
+
default: return false;
|
|
17624
|
+
}
|
|
17625
|
+
}
|
|
17626
|
+
/**
|
|
17627
|
+
* The span a property gets when nothing is declared.
|
|
17628
|
+
*
|
|
17629
|
+
* Deliberately coarse: three buckets, chosen by how much room the *editor*
|
|
17630
|
+
* needs, not by how important the field is. Importance is what `admin.form`
|
|
17631
|
+
* sections are for.
|
|
17632
|
+
*/
|
|
17633
|
+
function deriveSpan(property, isTitleProperty) {
|
|
17634
|
+
if (needsFullWidth(property)) return 4;
|
|
17635
|
+
if (isTitleProperty) return 4;
|
|
17636
|
+
switch (property.type) {
|
|
17637
|
+
case "number":
|
|
17638
|
+
case "boolean": return 1;
|
|
17639
|
+
case "date":
|
|
17640
|
+
case "geopoint":
|
|
17641
|
+
case "reference":
|
|
17642
|
+
case "relation": return 2;
|
|
17643
|
+
case "array": return 2;
|
|
17644
|
+
case "string": return 2;
|
|
17645
|
+
default: return 2;
|
|
17646
|
+
}
|
|
17647
|
+
}
|
|
17648
|
+
/**
|
|
17649
|
+
* Can the user still type this id?
|
|
17650
|
+
*
|
|
17651
|
+
* A `manual` id is a real field while creating and frozen once the row exists.
|
|
17652
|
+
* Every generated strategy (`uuid`, `cuid`, a raw SQL default) is never typed.
|
|
17653
|
+
* Getting this wrong in the "frozen" direction would make manual-id collections
|
|
17654
|
+
* uncreatable, so it fails towards showing the field.
|
|
17655
|
+
*/
|
|
17656
|
+
function isIdPropertyEditable(property, status) {
|
|
17657
|
+
if (!("isId" in property) || !property.isId) return true;
|
|
17658
|
+
if (status === "existing") return false;
|
|
17659
|
+
return property.isId === "manual";
|
|
17660
|
+
}
|
|
17661
|
+
function isIdProperty(property) {
|
|
17662
|
+
return Boolean(property && "isId" in property && property.isId);
|
|
17663
|
+
}
|
|
17664
|
+
/**
|
|
17665
|
+
* An audit timestamp the database maintains — `created_at`, `updated_at`.
|
|
17666
|
+
*
|
|
17667
|
+
* Not a guess from the name: `autoValue` says the column is written by the
|
|
17668
|
+
* system on create or update, so the field is never typed. Rendering it as an
|
|
17669
|
+
* input in the middle of the form promised an edit that cannot happen, and the
|
|
17670
|
+
* record block already shows both values — the same two dates twice on one
|
|
17671
|
+
* screen.
|
|
17672
|
+
*/
|
|
17673
|
+
function isAuditTimestamp(property) {
|
|
17674
|
+
return Boolean(property && property.type === "date" && property.autoValue);
|
|
17675
|
+
}
|
|
17676
|
+
/**
|
|
17677
|
+
* Close the trailing gap in each row.
|
|
17678
|
+
*
|
|
17679
|
+
* Without this a section of half-width fields with an odd count leaves a hole —
|
|
17680
|
+
* `name | sku` then `brand | ␣␣` — a field stranded beside half a row of
|
|
17681
|
+
* nothing, which reads as a mistake rather than a layout. The remainder is
|
|
17682
|
+
* spread across the row's derived fields rather than dumped on the last one, so
|
|
17683
|
+
* a lone half-width field becomes full width and a pair grows evenly. Fields
|
|
17684
|
+
* with an explicit span are never resized.
|
|
17685
|
+
*/
|
|
17686
|
+
function fillRows(fields) {
|
|
17687
|
+
const rows = [];
|
|
17688
|
+
let row = [];
|
|
17689
|
+
let used = 0;
|
|
17690
|
+
for (const field of fields) {
|
|
17691
|
+
if (used + field.span > GRID_COLUMNS && row.length) {
|
|
17692
|
+
rows.push(row);
|
|
17693
|
+
row = [];
|
|
17694
|
+
used = 0;
|
|
17695
|
+
}
|
|
17696
|
+
row.push(field);
|
|
17697
|
+
used += field.span;
|
|
17698
|
+
}
|
|
17699
|
+
if (row.length) rows.push(row);
|
|
17700
|
+
return rows.flatMap((entries) => {
|
|
17701
|
+
let gap = GRID_COLUMNS - entries.reduce((sum, f) => sum + f.span, 0);
|
|
17702
|
+
if (gap <= 0) return entries;
|
|
17703
|
+
const growable = entries.map((f, i) => [f, i]).filter(([f]) => !f.spanExplicit);
|
|
17704
|
+
if (!growable.length) return entries;
|
|
17705
|
+
const next = [...entries];
|
|
17706
|
+
let cursor = 0;
|
|
17707
|
+
while (gap > 0) {
|
|
17708
|
+
const [, index] = growable[cursor % growable.length];
|
|
17709
|
+
next[index] = {
|
|
17710
|
+
...next[index],
|
|
17711
|
+
span: next[index].span + 1
|
|
17712
|
+
};
|
|
17713
|
+
gap -= 1;
|
|
17714
|
+
cursor += 1;
|
|
17715
|
+
}
|
|
17716
|
+
return next;
|
|
17717
|
+
});
|
|
17718
|
+
}
|
|
17719
|
+
function buildField(key, collection, titlePropertyKey) {
|
|
17720
|
+
const property = collection.properties?.[key];
|
|
17721
|
+
if (!property) return collection.additionalFields?.some((f) => f.key === key) ? {
|
|
17722
|
+
key,
|
|
17723
|
+
span: 4,
|
|
17724
|
+
additional: true
|
|
17725
|
+
} : void 0;
|
|
17726
|
+
if (isHidden(property)) return void 0;
|
|
17727
|
+
const admin = property.admin;
|
|
17728
|
+
const explicit = admin?.span !== void 0;
|
|
17729
|
+
return {
|
|
17730
|
+
key,
|
|
17731
|
+
span: admin?.span ?? deriveSpan(property, key === titlePropertyKey),
|
|
17732
|
+
additional: false,
|
|
17733
|
+
spanExplicit: explicit
|
|
17734
|
+
};
|
|
17735
|
+
}
|
|
17736
|
+
/**
|
|
17737
|
+
* Resolve the layout for a collection's generated form.
|
|
17738
|
+
*
|
|
17739
|
+
* Never drops a field: anything not named by a section lands in a trailing
|
|
17740
|
+
* group, so adding a column to the database cannot make it silently invisible
|
|
17741
|
+
* in the panel.
|
|
17742
|
+
*/
|
|
17743
|
+
function resolveFormLayout({ collection, fieldKeys, status }) {
|
|
17744
|
+
const config = collection.form;
|
|
17745
|
+
const titlePropertyKey = collection.titleProperty;
|
|
17746
|
+
const available = /* @__PURE__ */ new Map();
|
|
17747
|
+
for (const key of fieldKeys) {
|
|
17748
|
+
const field = buildField(key, collection, titlePropertyKey);
|
|
17749
|
+
if (field) available.set(key, field);
|
|
17750
|
+
}
|
|
17751
|
+
const idKeys = [...available.keys()].filter((key) => isIdProperty(collection.properties?.[key]));
|
|
17752
|
+
if (idKeys.length === 1) {
|
|
17753
|
+
const property = collection.properties?.[idKeys[0]];
|
|
17754
|
+
if (!isIdPropertyEditable(property, status)) available.delete(idKeys[0]);
|
|
17755
|
+
}
|
|
17756
|
+
const showRecordMetaResolved = config?.showRecordMeta ?? !collection.hideIdFromForm;
|
|
17757
|
+
if (showRecordMetaResolved) for (const key of [...available.keys()]) {
|
|
17758
|
+
const property = collection.properties?.[key];
|
|
17759
|
+
if (config?.sidebar?.includes(key)) continue;
|
|
17760
|
+
if (isAuditTimestamp(property)) available.delete(key);
|
|
17761
|
+
}
|
|
17762
|
+
const sidebar = [];
|
|
17763
|
+
if (config?.sidebar) for (const key of config.sidebar) {
|
|
17764
|
+
const field = available.get(key);
|
|
17765
|
+
if (!field) continue;
|
|
17766
|
+
sidebar.push(field);
|
|
17767
|
+
available.delete(key);
|
|
17768
|
+
}
|
|
17769
|
+
const showRecordMeta = showRecordMetaResolved;
|
|
17770
|
+
const sections = [];
|
|
17771
|
+
if (config?.sections?.length) for (const section of config.sections) {
|
|
17772
|
+
const fields = [];
|
|
17773
|
+
for (const key of section.properties) {
|
|
17774
|
+
const field = available.get(key);
|
|
17775
|
+
if (!field) continue;
|
|
17776
|
+
fields.push(field);
|
|
17777
|
+
available.delete(key);
|
|
17778
|
+
}
|
|
17779
|
+
const titled = Boolean(section.title);
|
|
17780
|
+
sections.push({
|
|
17781
|
+
key: section.key,
|
|
17782
|
+
title: section.title,
|
|
17783
|
+
collapsible: section.collapsible ?? titled,
|
|
17784
|
+
collapsed: titled ? Boolean(section.collapsed) : false,
|
|
17785
|
+
fields
|
|
17786
|
+
});
|
|
17787
|
+
}
|
|
17788
|
+
const leftovers = fieldKeys.map((key) => available.get(key)).filter((f) => Boolean(f));
|
|
17789
|
+
if (leftovers.length) sections.push({
|
|
17790
|
+
key: sections.length ? "__other" : "__main",
|
|
17791
|
+
collapsible: false,
|
|
17792
|
+
collapsed: false,
|
|
17793
|
+
fields: leftovers
|
|
17794
|
+
});
|
|
17795
|
+
return {
|
|
17796
|
+
sections: sections.filter((s) => s.fields.length > 0).map((s) => ({
|
|
17797
|
+
...s,
|
|
17798
|
+
fields: fillRows(s.fields)
|
|
17799
|
+
})),
|
|
17800
|
+
sidebar,
|
|
17801
|
+
showRecordMeta,
|
|
17802
|
+
hasRail: sidebar.length > 0 || showRecordMeta
|
|
17803
|
+
};
|
|
17804
|
+
}
|
|
17805
|
+
//#endregion
|
|
17250
17806
|
//#region src/collections/navigation_utils.ts
|
|
17251
17807
|
function removeInitialAndTrailingSlashes(s) {
|
|
17252
17808
|
return removeInitialSlash(removeTrailingSlash(s));
|
|
@@ -17458,115 +18014,6 @@ function getParentReferencesFromPath(props) {
|
|
|
17458
18014
|
return result;
|
|
17459
18015
|
}
|
|
17460
18016
|
//#endregion
|
|
17461
|
-
//#region src/collections/property_presentation.ts
|
|
17462
|
-
function isReadOnly(property) {
|
|
17463
|
-
if (property.admin?.readOnly) return true;
|
|
17464
|
-
if (property.type === "date") {
|
|
17465
|
-
if (property.autoValue) return true;
|
|
17466
|
-
}
|
|
17467
|
-
if (property.type === "reference") return !property.path && !("Field" in (property.admin || {}) && property.admin?.Field);
|
|
17468
|
-
return false;
|
|
17469
|
-
}
|
|
17470
|
-
function isHidden(property) {
|
|
17471
|
-
return typeof property.admin?.disabled === "object" && Boolean(property.admin?.disabled.hidden);
|
|
17472
|
-
}
|
|
17473
|
-
function applyPropertyConditions(property, context) {
|
|
17474
|
-
const { conditions } = property;
|
|
17475
|
-
if (!conditions) return property;
|
|
17476
|
-
const result = { ...property };
|
|
17477
|
-
if (conditions.disabled) {
|
|
17478
|
-
if (evaluateCondition(conditions.disabled, context)) {
|
|
17479
|
-
result.admin = result.admin || {};
|
|
17480
|
-
result.admin.disabled = {
|
|
17481
|
-
clearOnDisabled: conditions.clearOnDisabled ?? false,
|
|
17482
|
-
disabledMessage: conditions.disabledMessage,
|
|
17483
|
-
hidden: false
|
|
17484
|
-
};
|
|
17485
|
-
}
|
|
17486
|
-
}
|
|
17487
|
-
if (conditions.hidden) {
|
|
17488
|
-
if (evaluateCondition(conditions.hidden, context)) {
|
|
17489
|
-
result.admin = result.admin || {};
|
|
17490
|
-
result.admin.disabled = {
|
|
17491
|
-
...typeof result.admin?.disabled === "object" ? result.admin.disabled : {},
|
|
17492
|
-
hidden: true,
|
|
17493
|
-
clearOnDisabled: conditions.clearOnDisabled ?? false
|
|
17494
|
-
};
|
|
17495
|
-
}
|
|
17496
|
-
}
|
|
17497
|
-
if (conditions.readOnly) {
|
|
17498
|
-
if (evaluateCondition(conditions.readOnly, context)) {
|
|
17499
|
-
result.admin = result.admin || {};
|
|
17500
|
-
result.admin.readOnly = true;
|
|
17501
|
-
}
|
|
17502
|
-
}
|
|
17503
|
-
if (conditions.required !== void 0) {
|
|
17504
|
-
const isRequired = evaluateCondition(conditions.required, context);
|
|
17505
|
-
result.validation = {
|
|
17506
|
-
...result.validation,
|
|
17507
|
-
required: isRequired,
|
|
17508
|
-
requiredMessage: conditions.requiredMessage
|
|
17509
|
-
};
|
|
17510
|
-
}
|
|
17511
|
-
if (context.isNew && conditions.defaultValue !== void 0) result.defaultValue = evaluateCondition(conditions.defaultValue, context);
|
|
17512
|
-
if ("enum" in result && result.enum && (conditions.enumConditions || conditions.allowedEnumValues || conditions.excludedEnumValues)) result.enum = applyEnumConditions(result.enum, conditions, context);
|
|
17513
|
-
if (result.type === "reference") {
|
|
17514
|
-
if (conditions.referencePath) result.path = evaluateCondition(conditions.referencePath, context);
|
|
17515
|
-
if (conditions.referenceFilter) {
|
|
17516
|
-
result.admin = result.admin || {};
|
|
17517
|
-
result.admin.fixedFilter = evaluateCondition(conditions.referenceFilter, context);
|
|
17518
|
-
}
|
|
17519
|
-
}
|
|
17520
|
-
if (result.type === "array") {
|
|
17521
|
-
if (conditions.canAddElements !== void 0) {
|
|
17522
|
-
result.admin = result.admin || {};
|
|
17523
|
-
result.admin.canAddElements = evaluateCondition(conditions.canAddElements, context);
|
|
17524
|
-
}
|
|
17525
|
-
if (conditions.sortable !== void 0) {
|
|
17526
|
-
result.admin = result.admin || {};
|
|
17527
|
-
result.admin.sortable = evaluateCondition(conditions.sortable, context);
|
|
17528
|
-
}
|
|
17529
|
-
}
|
|
17530
|
-
return result;
|
|
17531
|
-
}
|
|
17532
|
-
/**
|
|
17533
|
-
* Convert an object with numeric keys back to an array.
|
|
17534
|
-
* Firestore stores arrays as {"0": "a", "1": "b"} to avoid nested arrays.
|
|
17535
|
-
*/
|
|
17536
|
-
function objectToArray(obj) {
|
|
17537
|
-
if (Array.isArray(obj)) return obj.map(String);
|
|
17538
|
-
if (obj && typeof obj === "object") {
|
|
17539
|
-
const keys = Object.keys(obj);
|
|
17540
|
-
if (keys.length > 0 && keys.every((k) => !isNaN(Number(k)))) return keys.sort((a, b) => Number(a) - Number(b)).map((k) => obj[k]).filter((v) => typeof v === "string" || typeof v === "number").map(String);
|
|
17541
|
-
}
|
|
17542
|
-
return [];
|
|
17543
|
-
}
|
|
17544
|
-
/**
|
|
17545
|
-
* Apply enum-specific conditions to filter and modify enum values.
|
|
17546
|
-
*/
|
|
17547
|
-
function applyEnumConditions(enumValues, conditions, context) {
|
|
17548
|
-
let result = [...enumValues];
|
|
17549
|
-
if (conditions.allowedEnumValues) {
|
|
17550
|
-
const allowedArray = objectToArray(evaluateCondition(conditions.allowedEnumValues, context));
|
|
17551
|
-
if (allowedArray.length > 0) result = result.filter((ev) => allowedArray.includes(String(ev.id)));
|
|
17552
|
-
}
|
|
17553
|
-
if (conditions.excludedEnumValues) {
|
|
17554
|
-
const excludedArray = objectToArray(evaluateCondition(conditions.excludedEnumValues, context));
|
|
17555
|
-
if (excludedArray.length > 0) result = result.filter((ev) => !excludedArray.includes(String(ev.id)));
|
|
17556
|
-
}
|
|
17557
|
-
if (conditions.enumConditions) result = result.map((ev) => {
|
|
17558
|
-
const evConditions = conditions.enumConditions?.[ev.id];
|
|
17559
|
-
if (!evConditions) return ev;
|
|
17560
|
-
if (evConditions.hidden && evaluateCondition(evConditions.hidden, context)) return null;
|
|
17561
|
-
if (evConditions.disabled && evaluateCondition(evConditions.disabled, context)) return {
|
|
17562
|
-
...ev,
|
|
17563
|
-
disabled: true
|
|
17564
|
-
};
|
|
17565
|
-
return ev;
|
|
17566
|
-
}).filter((ev) => ev !== null);
|
|
17567
|
-
return result;
|
|
17568
|
-
}
|
|
17569
|
-
//#endregion
|
|
17570
18017
|
//#region src/collections/title-property.ts
|
|
17571
18018
|
/**
|
|
17572
18019
|
* How good a property is as the human-readable title of an entity.
|
|
@@ -17600,7 +18047,7 @@ var SCORE = {
|
|
|
17600
18047
|
* This is a *bonus* on top of the structural rules — never a requirement, and
|
|
17601
18048
|
* never the mechanism that keeps identifiers out of the title slot.
|
|
17602
18049
|
*/
|
|
17603
|
-
var TITLE_LIKE_KEYS = new Set([
|
|
18050
|
+
var TITLE_LIKE_KEYS = /* @__PURE__ */ new Set([
|
|
17604
18051
|
"name",
|
|
17605
18052
|
"fullname",
|
|
17606
18053
|
"displayname",
|
|
@@ -17730,6 +18177,40 @@ function getTitlePropertyCandidates(collection) {
|
|
|
17730
18177
|
return scored.map((candidate) => candidate.key);
|
|
17731
18178
|
}
|
|
17732
18179
|
/**
|
|
18180
|
+
* The relation a collection *leads* with, if it leads with one.
|
|
18181
|
+
*
|
|
18182
|
+
* A junction-shaped collection — a pipeline entry, a membership, a booking —
|
|
18183
|
+
* holds no label of its own: it is "this candidate, for that vacancy". The
|
|
18184
|
+
* general ranking puts relations last (they only read once the target
|
|
18185
|
+
* resolves), so the title slot would otherwise fall to whatever free text
|
|
18186
|
+
* happens to follow: a note, a comment. Preview surfaces that render one row
|
|
18187
|
+
* per entity (list, cards, board) prefer the leading relation instead.
|
|
18188
|
+
*
|
|
18189
|
+
* The decision is structural — the first property that could be a title, in the
|
|
18190
|
+
* order the developer declared (or ordered) them. Declaration order is a
|
|
18191
|
+
* statement about what the collection is about; property *names* are not
|
|
18192
|
+
* consulted here.
|
|
18193
|
+
*
|
|
18194
|
+
* Returns `undefined` when that first property is anything but a
|
|
18195
|
+
* single-cardinality relation, or when the collection states its own
|
|
18196
|
+
* `titleProperty`.
|
|
18197
|
+
*
|
|
18198
|
+
* @group Collections
|
|
18199
|
+
*/
|
|
18200
|
+
function getLeadingRelationTitleKey(collection) {
|
|
18201
|
+
if (!collection.properties) return void 0;
|
|
18202
|
+
if (collection.titleProperty) return void 0;
|
|
18203
|
+
const idKeys = new Set(getPrimaryKeys(collection));
|
|
18204
|
+
const foreignKeys = getForeignKeyColumns(collection);
|
|
18205
|
+
const order = collection.propertiesOrder ?? Object.keys(collection.properties);
|
|
18206
|
+
for (const key of order) {
|
|
18207
|
+
const property = collection.properties[key];
|
|
18208
|
+
if (!property || isPropertyBuilder(property)) continue;
|
|
18209
|
+
if (scoreTitleCandidate(property, key, idKeys, foreignKeys) === SCORE.DISQUALIFIED) continue;
|
|
18210
|
+
return property.type === "relation" ? key : void 0;
|
|
18211
|
+
}
|
|
18212
|
+
}
|
|
18213
|
+
/**
|
|
17733
18214
|
* The property that should fill the title slot for a collection, ignoring any
|
|
17734
18215
|
* concrete values. Prefer {@link getTitlePropertyKeyForValues} when an entity
|
|
17735
18216
|
* is at hand — it can skip candidates that happen to be empty or to hold an id.
|
|
@@ -17779,6 +18260,6 @@ function getTitlePropertyKeyForValues(collection, values, entityId) {
|
|
|
17779
18260
|
return candidates[0];
|
|
17780
18261
|
}
|
|
17781
18262
|
//#endregion
|
|
17782
|
-
export {
|
|
18263
|
+
export { AIIcon, AIModifiedIndicator, AdminModeControllerContext, AdminModeControllerProvider, AnalyticsContext, ApiConfigProvider, AuthControllerContext, CONTAINER_FULL_WIDTH, CollectionComponentOverrideProvider, CollectionResolverRegistrationContext, CollectionScopeContext, CollectionScopeProvider, ComponentOverrideContext, ConfirmationDialog, CrmDashboardDemo, CustomizationControllerContext, DEFAULT_API_PATH, DEFAULT_PAGE_SIZE, DataDriverContext, DataSourcesContext, DialogsControllerContext, DialogsProvider, EffectiveRoleControllerContext, EffectiveRoleControllerProvider, ErrorTooltip, ErrorView, FORM_CONTAINER_WIDTH, GlobalComponentOverrideProvider, IconForView, LanguageToggle, LoginView, ModeControllerContext, ModeControllerProvider, NavigationBlockerProvider, NotFoundPage, PluginProviderStack, REBASE_LOCALE_STORAGE_KEY, Rebase, RebaseAuth, RebaseClientInstanceContext, RebaseDataContext, RebaseI18nProvider, RebaseLogo, RebaseRegistryProvider, RebaseRouter, RebaseRoutes, SIDE_PANEL_DEFAULT_WIDTH, STUDIO_NAVIGATION_GROUPS, SchemaDriftBanner, SchemaDriftProvider, SnackbarProvider, StorageSourceContext, StorageSourcesContext, StudioBridgeContext, StudioBridgeProvider, StudioBridgeRegistryContext, StudioBridgeRegistryProvider, UIReferenceView, UIStyleGuide, UnsavedChangesDialog, UserConfigurationPersistenceContext, UserDisplay, UserSelectPopover, UserSettingsView, addInitialSlash, apiBaseOf, applyPropertyConditions, buildCollapsedDefaults, buildEnumLabel, clearAuthConfigCache, clearFetchCache, createAuthConfigCache, createFormexStub, deleteEntityWithCallbacks, deriveSpan, en, es, fetchAuthConfig, fillRows, flattenKeys, getAdminEntityChildViews, getAdminSubcollections, getCollectionBySlugWithin, getCollectionPathsCombinations, getColorScheme, getColumnKeysForProperty, getEntityFromCache, getEntityFromMemoryCache, getEntityImagePreviewPropertyKey, getEntityPreviewKeys, getEntityTitlePropertyKey, getFormFieldKeys, getIcon, getLastSegment, getLeadingRelationTitleKey, getLocalChangesBackup, getNavigationEntriesFromPath, getParentReferencesFromPath, getRelationIncludeParams, getRowHeight, getSubcollectionColumnId, getTitlePropertyCandidates, getTitlePropertyKey, getTitlePropertyKeyForValues, iconsSearch, isAuditTimestamp, isEnumValueDisabled, isFilterableRelation, isHidden, isIdPropertyEditable, isReadOnly, isSchemaDriftError, looksLikeIdentifierValue, populateFetchCache, removeEntityFromCache, removeEntityFromMemoryCache, removeInitialAndTrailingSlashes, removeInitialSlash, removeTrailingSlash, resolveCollectionPathIds, resolveComponentRef, resolveDefaultSelectedView, resolveFilterOperators, resolveFormLayout, saveEntityToCache, saveEntityToMemoryCache, saveEntityWithCallbacks, useAdminModeController, useAnalyticsController, useApiBase, useApiConfig, useAuthController, useAuthSubscription, useBackendStorageSource, useBridgeRegistration, useBrowserTitleAndIcon, useBuildAdminModeController, useBuildEffectiveRoleController, useBuildLocalConfigurationPersistence, useBuildModeController, useClipboard, useCollapsedGroups, useCollection, useCollectionScope, useColumnIds, useComponentOverride, useCustomizationController, useData, useDataSources, useDataTableController, useDebouncedData, useDialogsController, useEffectiveRoleController, useFetch, useLargeLayout, useModeController, useNavigationBlocker, usePermissions, useRebaseAuthController, useRebaseClient, useRebaseContext, useRebaseRegistry, useRebaseRegistryDispatch, useRelationSelector, useResolvedComponent, useRestoreScroll, useSchemaDriftContext, useScrollRestoration, useSlot, useSnackbarController, useStorageSource, useStorageSources, useStorageUploadController, useStudioBreadcrumbs, useStudioCapabilities, useStudioCollectionRegistry, useStudioNavigationState, useStudioSidePanelController, useStudioUrlController, useTranslation, useUnsavedChangesDialog, useUserConfigurationPersistence };
|
|
17783
18264
|
|
|
17784
18265
|
//# sourceMappingURL=index.es.js.map
|