@juicemantics/veloiq-ui 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +56 -1
- package/dist/index.d.ts +56 -1
- package/dist/index.js +897 -41
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +896 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React6, { createContext, useContext, useMemo, useState, useRef, useEffect, useCallback, useLayoutEffect, useSyncExternalStore, useId, useImperativeHandle } from 'react';
|
|
2
2
|
import { ThemedLayoutV2, Show, List, useForm, DeleteButton, useTable, RefineThemes, Breadcrumb as Breadcrumb$1, Create, useSelect, Edit, ListButton, EditButton, RefreshButton } from '@refinedev/antd';
|
|
3
3
|
import { useMenu, useGo, useGetIdentity, useLogout, useOne, useApiUrl, useInvalidate, useCan, useCustom, useLogin, useWarnAboutChange } from '@refinedev/core';
|
|
4
|
-
import { Typography, Menu, theme, Layout, Space, AutoComplete, Input, Spin, Grid, Form, Drawer, Modal, Button, Tooltip, Skeleton, message, Switch, Divider, Tabs, Alert, Card, Table, Select, DatePicker, InputNumber, Checkbox, Pagination, Collapse, Breadcrumb, Tree, ConfigProvider,
|
|
5
|
-
import { SearchOutlined, LockOutlined, LogoutOutlined, InfoCircleOutlined, SaveOutlined, UnorderedListOutlined, DownloadOutlined, SettingOutlined, PlusOutlined, LinkOutlined, ShareAltOutlined, BarChartOutlined, ColumnHeightOutlined, SwapOutlined, FilterOutlined, ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, ArrowLeftOutlined, ArrowRightOutlined, FileTextOutlined, BugOutlined, EyeOutlined, EditOutlined, FilePdfOutlined, CloseCircleOutlined, DownOutlined, UserOutlined, CheckCircleOutlined, CopyOutlined, ApartmentOutlined, SaveFilled, CalendarOutlined, MenuOutlined, MenuUnfoldOutlined, MenuFoldOutlined, LayoutOutlined, AppstoreOutlined, CommentOutlined, MinusSquareOutlined, FullscreenOutlined, CloseOutlined, DatabaseOutlined, ShopOutlined, BookOutlined,
|
|
4
|
+
import { Typography, Menu, theme, Layout, Space, AutoComplete, Input, Spin, Grid, Form, Drawer, Modal, Button, Tooltip, Skeleton, message, Switch, Divider, Tabs, Alert, Card, Table, Select, DatePicker, InputNumber, Checkbox, Pagination, Collapse, Breadcrumb, Tree, ConfigProvider, Empty, Tag, List as List$1, Popover, Dropdown, Avatar, TimePicker, Upload } from 'antd';
|
|
5
|
+
import { SearchOutlined, LockOutlined, LogoutOutlined, InfoCircleOutlined, SaveOutlined, UnorderedListOutlined, DownloadOutlined, SettingOutlined, PlusOutlined, LinkOutlined, ShareAltOutlined, BarChartOutlined, ColumnHeightOutlined, SwapOutlined, FilterOutlined, ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, ArrowLeftOutlined, ArrowRightOutlined, FileTextOutlined, BugOutlined, EyeOutlined, EditOutlined, FilePdfOutlined, CloseCircleOutlined, DownOutlined, UserOutlined, ReloadOutlined, ClockCircleOutlined, PushpinFilled, PushpinOutlined, DashboardOutlined, CheckCircleOutlined, CopyOutlined, ApartmentOutlined, SaveFilled, CalendarOutlined, MenuOutlined, MenuUnfoldOutlined, MenuFoldOutlined, LayoutOutlined, AppstoreOutlined, CommentOutlined, MinusSquareOutlined, FullscreenOutlined, CloseOutlined, DatabaseOutlined, ShopOutlined, BookOutlined, UploadOutlined, FolderOutlined, FileOutlined, RightOutlined } from '@ant-design/icons';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
7
|
import { useNavigate, useParams, useSearchParams, useLocation, Link, UNSAFE_RouteContext } from 'react-router-dom';
|
|
8
8
|
import { createPortal } from 'react-dom';
|
|
@@ -858,7 +858,7 @@ var LayoutWrapper = ({
|
|
|
858
858
|
label: "Confirm Password",
|
|
859
859
|
dependencies: ["new_password"],
|
|
860
860
|
rules: [{ required: true }, ({ getFieldValue }) => ({
|
|
861
|
-
validator(
|
|
861
|
+
validator(_39, value) {
|
|
862
862
|
if (!value || getFieldValue("new_password") === value) return Promise.resolve();
|
|
863
863
|
return Promise.reject(new Error("Passwords do not match"));
|
|
864
864
|
}
|
|
@@ -2598,19 +2598,19 @@ function Ut({
|
|
|
2598
2598
|
const { defaultLayoutDeferred: Y, derivedPanelConstraints: Ee, layout: ce } = j.next;
|
|
2599
2599
|
if (Y || Ee.length === 0)
|
|
2600
2600
|
return;
|
|
2601
|
-
const ut = R.panels.map(({ id:
|
|
2602
|
-
R.mutableState.layouts[ut] = ce, Ee.forEach((
|
|
2603
|
-
if (
|
|
2601
|
+
const ut = R.panels.map(({ id: _39 }) => _39).join(",");
|
|
2602
|
+
R.mutableState.layouts[ut] = ce, Ee.forEach((_39) => {
|
|
2603
|
+
if (_39.collapsible) {
|
|
2604
2604
|
const { layout: ge } = j.prev ?? {};
|
|
2605
2605
|
if (ge) {
|
|
2606
2606
|
const ft = I(
|
|
2607
|
-
|
|
2608
|
-
ce[
|
|
2607
|
+
_39.collapsedSize,
|
|
2608
|
+
ce[_39.panelId]
|
|
2609
2609
|
), dt = I(
|
|
2610
|
-
|
|
2611
|
-
ge[
|
|
2610
|
+
_39.collapsedSize,
|
|
2611
|
+
ge[_39.panelId]
|
|
2612
2612
|
);
|
|
2613
|
-
ft && !dt && (R.mutableState.expandedPanelSizes[
|
|
2613
|
+
ft && !dt && (R.mutableState.expandedPanelSizes[_39.panelId] = ge[_39.panelId]);
|
|
2614
2614
|
}
|
|
2615
2615
|
}
|
|
2616
2616
|
});
|
|
@@ -3989,7 +3989,7 @@ var parseInlineStyle = (styleText) => {
|
|
|
3989
3989
|
return styleText.split(";").map((chunk) => chunk.trim()).filter(Boolean).reduce((acc, rule) => {
|
|
3990
3990
|
const [rawKey, rawValue] = rule.split(":").map((part) => part.trim());
|
|
3991
3991
|
if (!rawKey || !rawValue) return acc;
|
|
3992
|
-
const camelKey = rawKey.replace(/-([a-z])/g, (
|
|
3992
|
+
const camelKey = rawKey.replace(/-([a-z])/g, (_39, char) => char.toUpperCase());
|
|
3993
3993
|
acc[camelKey] = rawValue;
|
|
3994
3994
|
return acc;
|
|
3995
3995
|
}, {});
|
|
@@ -6595,6 +6595,68 @@ var RelationsExplorer = ({ model, record, allModels, isActive = true }) => {
|
|
|
6595
6595
|
] })
|
|
6596
6596
|
] });
|
|
6597
6597
|
};
|
|
6598
|
+
|
|
6599
|
+
// src/providers/constants.ts
|
|
6600
|
+
var API_URL3 = "/api";
|
|
6601
|
+
|
|
6602
|
+
// src/pages/dashboard/hooks/usePinRecord.ts
|
|
6603
|
+
function usePinRecord(resource, recordId) {
|
|
6604
|
+
const [pinned, setPinned] = useState(null);
|
|
6605
|
+
const [loading, setLoading] = useState(false);
|
|
6606
|
+
useEffect(() => {
|
|
6607
|
+
if (!resource || recordId === void 0 || recordId === null || recordId === "") return;
|
|
6608
|
+
let cancelled = false;
|
|
6609
|
+
authenticatedFetch(
|
|
6610
|
+
`${API_URL3}/dashboard/pinned-records/check?resource=${encodeURIComponent(resource)}&record_id=${encodeURIComponent(String(recordId))}`
|
|
6611
|
+
).then((r) => r.json()).then((d) => {
|
|
6612
|
+
if (!cancelled) setPinned(Boolean(d.pinned));
|
|
6613
|
+
}).catch(() => {
|
|
6614
|
+
if (!cancelled) setPinned(false);
|
|
6615
|
+
});
|
|
6616
|
+
return () => {
|
|
6617
|
+
cancelled = true;
|
|
6618
|
+
};
|
|
6619
|
+
}, [resource, recordId]);
|
|
6620
|
+
const pin = useCallback(async () => {
|
|
6621
|
+
if (!resource || recordId === void 0) return;
|
|
6622
|
+
setLoading(true);
|
|
6623
|
+
try {
|
|
6624
|
+
await authenticatedFetch(`${API_URL3}/dashboard/pinned-records`, {
|
|
6625
|
+
method: "POST",
|
|
6626
|
+
headers: { "Content-Type": "application/json" },
|
|
6627
|
+
body: JSON.stringify({ resource, record_id: String(recordId) })
|
|
6628
|
+
});
|
|
6629
|
+
setPinned(true);
|
|
6630
|
+
} finally {
|
|
6631
|
+
setLoading(false);
|
|
6632
|
+
}
|
|
6633
|
+
}, [resource, recordId]);
|
|
6634
|
+
const unpin = useCallback(async () => {
|
|
6635
|
+
if (!resource || recordId === void 0) return;
|
|
6636
|
+
setLoading(true);
|
|
6637
|
+
try {
|
|
6638
|
+
await authenticatedFetch(
|
|
6639
|
+
`${API_URL3}/dashboard/pinned-records/${encodeURIComponent(resource)}/${encodeURIComponent(String(recordId))}`,
|
|
6640
|
+
{ method: "DELETE" }
|
|
6641
|
+
);
|
|
6642
|
+
setPinned(false);
|
|
6643
|
+
} finally {
|
|
6644
|
+
setLoading(false);
|
|
6645
|
+
}
|
|
6646
|
+
}, [resource, recordId]);
|
|
6647
|
+
const toggle = useCallback(() => pinned ? unpin() : pin(), [pinned, pin, unpin]);
|
|
6648
|
+
return { pinned, loading, pin, unpin, toggle };
|
|
6649
|
+
}
|
|
6650
|
+
async function unpinRecords(resource, recordIds) {
|
|
6651
|
+
await Promise.all(
|
|
6652
|
+
recordIds.map(
|
|
6653
|
+
(id) => authenticatedFetch(
|
|
6654
|
+
`${API_URL3}/dashboard/pinned-records/${encodeURIComponent(resource)}/${encodeURIComponent(String(id))}`,
|
|
6655
|
+
{ method: "DELETE" }
|
|
6656
|
+
)
|
|
6657
|
+
)
|
|
6658
|
+
);
|
|
6659
|
+
}
|
|
6598
6660
|
var _15 = window._ || ((text) => text);
|
|
6599
6661
|
var useShowActionsPreferences = (model, allModels, record, saveButtonProps) => {
|
|
6600
6662
|
const apiUrl = useApiUrl();
|
|
@@ -6704,6 +6766,9 @@ var useShowActionsPreferences = (model, allModels, record, saveButtonProps) => {
|
|
|
6704
6766
|
] });
|
|
6705
6767
|
const { id: urlId } = useParams();
|
|
6706
6768
|
const effectiveRecord = record ?? (urlId ? { eid: Number(urlId) } : void 0);
|
|
6769
|
+
const recordId = effectiveRecord?.eid ?? effectiveRecord?.id ?? urlId;
|
|
6770
|
+
const resource = model.resource || model.name;
|
|
6771
|
+
const { pinned, loading: pinLoading, toggle: togglePin } = usePinRecord(resource, recordId);
|
|
6707
6772
|
const { metadataButton, metadataModal } = useMetadataModal(model, allModels);
|
|
6708
6773
|
const [exploreOpen, setExploreOpen] = useState(false);
|
|
6709
6774
|
const headerButtons = ({ defaultButtons }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -6711,6 +6776,15 @@ var useShowActionsPreferences = (model, allModels, record, saveButtonProps) => {
|
|
|
6711
6776
|
metadataModal,
|
|
6712
6777
|
/* @__PURE__ */ jsx(Popover, { content: actionsSettingsContent, title: _15("Actions"), trigger: "hover", children: /* @__PURE__ */ jsx(Button, { size: "small", icon: /* @__PURE__ */ jsx(SettingOutlined, {}) }) }),
|
|
6713
6778
|
/* @__PURE__ */ jsx("span", { style: { marginInlineStart: 10 } }),
|
|
6779
|
+
pinned !== null && /* @__PURE__ */ jsx(Tooltip, { title: pinned ? _15("Unpin") : _15("Pin to dashboard"), children: /* @__PURE__ */ jsx(
|
|
6780
|
+
Button,
|
|
6781
|
+
{
|
|
6782
|
+
size: "small",
|
|
6783
|
+
icon: pinned ? /* @__PURE__ */ jsx(PushpinFilled, { style: { color: "#faad14" } }) : /* @__PURE__ */ jsx(PushpinOutlined, {}),
|
|
6784
|
+
onClick: togglePin,
|
|
6785
|
+
loading: pinLoading
|
|
6786
|
+
}
|
|
6787
|
+
) }),
|
|
6714
6788
|
/* @__PURE__ */ jsx(Tooltip, { title: _15("Explore"), children: /* @__PURE__ */ jsx(Button, { size: "small", icon: /* @__PURE__ */ jsx(ApartmentOutlined, {}), onClick: () => setExploreOpen(true) }) }),
|
|
6715
6789
|
/* @__PURE__ */ jsx(
|
|
6716
6790
|
Modal,
|
|
@@ -7657,7 +7731,7 @@ var DynamicCreate = ({ model: modelProp, allModels, journeyCallbacks, injectedVa
|
|
|
7657
7731
|
const prefix = useReadonly ? "pc" : "cr";
|
|
7658
7732
|
return /* @__PURE__ */ jsxs("div", { style: { border: `1px solid ${token.colorBorder}`, borderRadius: 8, padding: "6px 6px", marginBottom: 6 }, children: [
|
|
7659
7733
|
/* @__PURE__ */ jsx(Title2, { level: 5, style: { margin: 0, marginBottom: 6, color: "#1677ff" }, children: _23(section) }),
|
|
7660
|
-
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((
|
|
7734
|
+
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((_39, rowIdx) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: maxCol }).map((_40, colIdx) => {
|
|
7661
7735
|
const cellItems = normalized.filter((r) => r.row === rowIdx + 1 && r.column === colIdx + 1);
|
|
7662
7736
|
return /* @__PURE__ */ jsx("td", { style: { padding: "0 4px", verticalAlign: "top", width: `${100 / maxCol}%` }, children: cellItems.map(
|
|
7663
7737
|
(item, idx) => useReadonly ? renderReadonlyCell(item, idx) : renderFormCell(item, idx)
|
|
@@ -8277,7 +8351,7 @@ var DynamicEdit = ({ model: modelProp, allModels, topContent, extraHeaderButtons
|
|
|
8277
8351
|
},
|
|
8278
8352
|
children: [
|
|
8279
8353
|
/* @__PURE__ */ jsx(Title3, { level: 5, style: { margin: 0, color: "#1677ff" }, children: _24(section) }),
|
|
8280
|
-
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((
|
|
8354
|
+
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((_39, rowIndex) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: maxCol }).map((_40, colIndex) => {
|
|
8281
8355
|
const cellItems = normalized.filter(
|
|
8282
8356
|
(item) => item.row === rowIndex + 1 && item.column === colIndex + 1
|
|
8283
8357
|
);
|
|
@@ -8490,7 +8564,7 @@ var DynamicEdit = ({ model: modelProp, allModels, topContent, extraHeaderButtons
|
|
|
8490
8564
|
const maxCol = Math.max(1, ...normalized.map((r) => r.column));
|
|
8491
8565
|
return /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, border: `1px solid ${token.colorBorder}`, borderRadius: 8, padding: "2px 6px" }, children: [
|
|
8492
8566
|
/* @__PURE__ */ jsx(Title3, { level: 5, style: { margin: 0, color: "#1677ff" }, children: _24(section) }),
|
|
8493
|
-
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((
|
|
8567
|
+
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((_39, ri) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: maxCol }).map((_40, ci) => {
|
|
8494
8568
|
const cellItems = normalized.filter((item) => item.row === ri + 1 && item.column === ci + 1);
|
|
8495
8569
|
return /* @__PURE__ */ jsx("td", { style: { padding: "0 4px", verticalAlign: "top", width: `${100 / maxCol}%` }, children: cellItems.map((item, idx) => {
|
|
8496
8570
|
if (item.attribute_or_relation_type === "nlsentence") {
|
|
@@ -8811,7 +8885,7 @@ var useStandardShowTabs = (model, record, allModels, actionsState, editForm, ove
|
|
|
8811
8885
|
},
|
|
8812
8886
|
children: [
|
|
8813
8887
|
/* @__PURE__ */ jsx(Title4, { level: 5, style: { margin: 0, color: "#1677ff" }, children: _25(section) }),
|
|
8814
|
-
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((
|
|
8888
|
+
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((_39, rowIndex) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: maxCol }).map((_40, colIndex) => {
|
|
8815
8889
|
const cellItems = normalized.filter(
|
|
8816
8890
|
(item) => item.row === rowIndex + 1 && item.column === colIndex + 1
|
|
8817
8891
|
);
|
|
@@ -9004,7 +9078,7 @@ var useStandardShowTabs = (model, record, allModels, actionsState, editForm, ove
|
|
|
9004
9078
|
const maxCol = Math.max(1, ...normalized.map((r) => r.column));
|
|
9005
9079
|
return /* @__PURE__ */ jsxs("div", { style: { flex: 1, minWidth: 0, border: `1px solid ${token.colorBorder}`, borderRadius: 8, padding: "6px 6px" }, children: [
|
|
9006
9080
|
/* @__PURE__ */ jsx(Title4, { level: 5, style: { margin: 0, color: "#1677ff" }, children: _25(section) }),
|
|
9007
|
-
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((
|
|
9081
|
+
/* @__PURE__ */ jsx("table", { style: { width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }, children: /* @__PURE__ */ jsx("tbody", { children: Array.from({ length: maxRow }).map((_39, ri) => /* @__PURE__ */ jsx("tr", { children: Array.from({ length: maxCol }).map((_40, ci) => {
|
|
9008
9082
|
const cellItems = normalized.filter((item) => item.row === ri + 1 && item.column === ci + 1);
|
|
9009
9083
|
return /* @__PURE__ */ jsx("td", { style: { padding: "0 4px", verticalAlign: "top", width: `${100 / maxCol}%` }, children: cellItems.map((item) => {
|
|
9010
9084
|
if (item.attribute_or_relation_type === "nlsentence") {
|
|
@@ -9909,7 +9983,7 @@ var RelatedObjectsEditableList = ({ rel, record, allModels }) => {
|
|
|
9909
9983
|
setPage(p);
|
|
9910
9984
|
}
|
|
9911
9985
|
},
|
|
9912
|
-
onShowSizeChange: (
|
|
9986
|
+
onShowSizeChange: (_39, newPageSize) => {
|
|
9913
9987
|
setPageSize(newPageSize);
|
|
9914
9988
|
setPage(1);
|
|
9915
9989
|
},
|
|
@@ -12369,7 +12443,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
|
|
|
12369
12443
|
setCurrentPage(1);
|
|
12370
12444
|
}
|
|
12371
12445
|
},
|
|
12372
|
-
onShowSizeChange: (
|
|
12446
|
+
onShowSizeChange: (_39, newPageSize) => {
|
|
12373
12447
|
if (newPageSize && newPageSize !== pageSize) {
|
|
12374
12448
|
setPageSize(newPageSize);
|
|
12375
12449
|
setCurrentPage(1);
|
|
@@ -12379,7 +12453,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
|
|
|
12379
12453
|
size: "small",
|
|
12380
12454
|
rowKey: (row) => row?.__relationKey || row?.eid || row?.id || JSON.stringify(row),
|
|
12381
12455
|
locale: filteredRows.length === 0 ? { emptyText: /* @__PURE__ */ jsx("span", { style: { display: "inline-block", fontSize: 12, color: "#8c8c8c" }, children: _30("No related records") }) } : void 0,
|
|
12382
|
-
onChange: (
|
|
12456
|
+
onChange: (_39, filters, sorter, extra) => {
|
|
12383
12457
|
const nextFilters = {};
|
|
12384
12458
|
Object.entries(filters || {}).forEach(([key, values]) => {
|
|
12385
12459
|
if (!values) return;
|
|
@@ -13740,7 +13814,7 @@ var renderRelationBlock = ({
|
|
|
13740
13814
|
};
|
|
13741
13815
|
var _32 = window._ || ((text) => text);
|
|
13742
13816
|
var { Title: Title7 } = Typography;
|
|
13743
|
-
var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbedded = false, showActions = true, showCreate = true, layoutPreferenceType, listViewType, rowSelection, extraHeaderButtons, bulkActions }) => {
|
|
13817
|
+
var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbedded = false, showActions = true, showCreate = true, layoutPreferenceType, listViewType, rowSelection, extraHeaderButtons, bulkActions, preferencesResourceOverride, defaultListVisible }) => {
|
|
13744
13818
|
const model = useRoleFilteredModel(modelProp);
|
|
13745
13819
|
applyI18nLabelsToModel(model);
|
|
13746
13820
|
applyI18nLabelsToModels(allModels);
|
|
@@ -13751,6 +13825,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
13751
13825
|
const invalidate = useInvalidate();
|
|
13752
13826
|
const apiUrl = useApiUrl();
|
|
13753
13827
|
const resourceIdentifier = resolveResourcePath(model.resource || model.name, allModels);
|
|
13828
|
+
const prefsKey = preferencesResourceOverride ?? resourceIdentifier;
|
|
13754
13829
|
const { data: canDeleteData } = useCan({ resource: resourceIdentifier, action: "delete" });
|
|
13755
13830
|
const { data: canEditData } = useCan({ resource: resourceIdentifier, action: "edit" });
|
|
13756
13831
|
const canBulkDelete = canDeleteData?.can !== false;
|
|
@@ -13801,7 +13876,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
13801
13876
|
const galleryImageHeight = viewSettings?.galleryImageHeight ?? 140;
|
|
13802
13877
|
const calendarDateFieldOptions = useMemo(() => getCalendarDateFieldOptions(model.fields), [model.fields]);
|
|
13803
13878
|
const [localSearch, setLocalSearch] = useState("");
|
|
13804
|
-
const [listVisible, setListVisible] = useState(true);
|
|
13879
|
+
const [listVisible, setListVisible] = useState(defaultListVisible ?? true);
|
|
13805
13880
|
const [isTdFlipped, setIsTdFlipped] = useState(false);
|
|
13806
13881
|
const [pageSize, setPageSize] = useState(10);
|
|
13807
13882
|
const [galleryPage, setGalleryPage] = useState(1);
|
|
@@ -14410,7 +14485,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14410
14485
|
}
|
|
14411
14486
|
}, [numericFields, rankingFieldKey, rankingMode]);
|
|
14412
14487
|
const resetLayoutDefaults = useCallback(() => {
|
|
14413
|
-
setListVisible(true);
|
|
14488
|
+
setListVisible(defaultListVisible ?? true);
|
|
14414
14489
|
setAnalyzeOpen(false);
|
|
14415
14490
|
setIsAnalyzeVertical(false);
|
|
14416
14491
|
setIsAnalyzeFirst(false);
|
|
@@ -14419,7 +14494,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14419
14494
|
setSelectedColumnKeys(null);
|
|
14420
14495
|
setColumnOrder(null);
|
|
14421
14496
|
setTotalsSummaryFunctions({});
|
|
14422
|
-
}, [isEmbedded]);
|
|
14497
|
+
}, [isEmbedded, defaultListVisible]);
|
|
14423
14498
|
const resetAnalyzeDefaults = useCallback(() => {
|
|
14424
14499
|
setCategoryField1(categoricalFields[0]?.key ?? null);
|
|
14425
14500
|
setCategoryField2(categoricalFields.length > 1 ? categoricalFields[1].key : null);
|
|
@@ -14432,7 +14507,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14432
14507
|
}, [categoricalFields, numericFields]);
|
|
14433
14508
|
const persistCurrentViewNames = useCallback(async (nextSelected, nextCurrent) => {
|
|
14434
14509
|
try {
|
|
14435
|
-
const resourceKey =
|
|
14510
|
+
const resourceKey = prefsKey;
|
|
14436
14511
|
await authenticatedFetch(`${apiUrl}/views/preferences/view`, {
|
|
14437
14512
|
method: "POST",
|
|
14438
14513
|
headers: { "Content-Type": "application/json" },
|
|
@@ -14445,9 +14520,9 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14445
14520
|
});
|
|
14446
14521
|
} catch {
|
|
14447
14522
|
}
|
|
14448
|
-
}, [apiUrl, model.name, model.resource, allModels]);
|
|
14523
|
+
}, [apiUrl, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14449
14524
|
const loadViewNames = useCallback(async () => {
|
|
14450
|
-
const resourceKey =
|
|
14525
|
+
const resourceKey = prefsKey;
|
|
14451
14526
|
setIsLoadingViewNames(true);
|
|
14452
14527
|
try {
|
|
14453
14528
|
const response = await authenticatedFetch(`${apiUrl}/views/preferences?resource=${encodeURIComponent(resourceKey)}&preference_type=__all__`);
|
|
@@ -14490,7 +14565,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14490
14565
|
setViewNamesLoaded(true);
|
|
14491
14566
|
setIsLoadingViewNames(false);
|
|
14492
14567
|
}
|
|
14493
|
-
}, [apiUrl, model.name, model.resource, allModels]);
|
|
14568
|
+
}, [apiUrl, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14494
14569
|
const openSaveViewModalFor = useCallback((target) => {
|
|
14495
14570
|
setSaveViewName(currentViewName || getDefaultViewName());
|
|
14496
14571
|
setSaveViewAsNew(false);
|
|
@@ -14539,7 +14614,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14539
14614
|
return;
|
|
14540
14615
|
}
|
|
14541
14616
|
try {
|
|
14542
|
-
const resourceKey =
|
|
14617
|
+
const resourceKey = prefsKey;
|
|
14543
14618
|
const response = await authenticatedFetch(`${apiUrl}/views/preferences/view`, {
|
|
14544
14619
|
method: "POST",
|
|
14545
14620
|
headers: { "Content-Type": "application/json" },
|
|
@@ -14563,7 +14638,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14563
14638
|
okButtonProps: { danger: true },
|
|
14564
14639
|
onOk: async () => {
|
|
14565
14640
|
try {
|
|
14566
|
-
const resourceKey =
|
|
14641
|
+
const resourceKey = prefsKey;
|
|
14567
14642
|
const response = await authenticatedFetch(`${apiUrl}/views/preferences/view`, {
|
|
14568
14643
|
method: "POST",
|
|
14569
14644
|
headers: { "Content-Type": "application/json" },
|
|
@@ -14582,7 +14657,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14582
14657
|
}, [apiUrl, currentViewName, model.name, model.resource, allModels, loadViewNames]);
|
|
14583
14658
|
const persistLayoutPreferences = useCallback(async (viewName) => {
|
|
14584
14659
|
if (!resolvedLayoutPreferenceType) return;
|
|
14585
|
-
const resourceKey =
|
|
14660
|
+
const resourceKey = prefsKey;
|
|
14586
14661
|
const resolvedViewName = normalizeViewName(viewName);
|
|
14587
14662
|
const preferences = {
|
|
14588
14663
|
listVisible,
|
|
@@ -14623,9 +14698,9 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14623
14698
|
} finally {
|
|
14624
14699
|
setIsSavingLayoutPrefs(false);
|
|
14625
14700
|
}
|
|
14626
|
-
}, [apiUrl, analyzeOpen, columnFiltersSelected, columnOrder, columnSort, filtersCollapsed, filterRules, isAnalyzeFirst, isAnalyzeVertical, resolvedLayoutPreferenceType, listVisible, pageSize, selectedColumnKeys, totalsSummaryFunctions, model.name, model.resource, allModels]);
|
|
14701
|
+
}, [apiUrl, analyzeOpen, columnFiltersSelected, columnOrder, columnSort, filtersCollapsed, filterRules, isAnalyzeFirst, isAnalyzeVertical, resolvedLayoutPreferenceType, listVisible, pageSize, selectedColumnKeys, totalsSummaryFunctions, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14627
14702
|
const persistAnalyzePreferences = useCallback(async (viewName) => {
|
|
14628
|
-
const resourceKey =
|
|
14703
|
+
const resourceKey = prefsKey;
|
|
14629
14704
|
const resolvedViewName = normalizeViewName(viewName);
|
|
14630
14705
|
const preferences = {
|
|
14631
14706
|
categoryField1,
|
|
@@ -14654,7 +14729,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14654
14729
|
} finally {
|
|
14655
14730
|
setIsSavingAnalyzePrefs(false);
|
|
14656
14731
|
}
|
|
14657
|
-
}, [apiUrl, categoryField1, categoryField2, chartType, selectedSeriesKeys, summaryFn, rankingMode, rankingFieldKey, rankingN, model.name, model.resource, allModels]);
|
|
14732
|
+
}, [apiUrl, categoryField1, categoryField2, chartType, selectedSeriesKeys, summaryFn, rankingMode, rankingFieldKey, rankingN, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14658
14733
|
const handleConfirmSaveView = useCallback(async () => {
|
|
14659
14734
|
if (!pendingSaveTarget) return;
|
|
14660
14735
|
const viewName = normalizeViewName(saveViewName || currentViewName);
|
|
@@ -14698,7 +14773,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14698
14773
|
resetAnalyzeDefaults();
|
|
14699
14774
|
}, [currentViewName, resetAnalyzeDefaults, resetLayoutDefaults, viewNamesLoaded]);
|
|
14700
14775
|
useEffect(() => {
|
|
14701
|
-
const resourceKey =
|
|
14776
|
+
const resourceKey = prefsKey;
|
|
14702
14777
|
const viewKey = `${resourceKey}::${currentViewName}`;
|
|
14703
14778
|
if (analyzePrefsResourceRef.current !== viewKey) {
|
|
14704
14779
|
analyzePrefsLoadedRef.current = false;
|
|
@@ -14746,10 +14821,10 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14746
14821
|
return () => {
|
|
14747
14822
|
cancelled = true;
|
|
14748
14823
|
};
|
|
14749
|
-
}, [apiUrl, currentViewName, model.name, model.resource, allModels]);
|
|
14824
|
+
}, [apiUrl, currentViewName, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14750
14825
|
useEffect(() => {
|
|
14751
14826
|
if (!resolvedLayoutPreferenceType) return;
|
|
14752
|
-
const resourceKey =
|
|
14827
|
+
const resourceKey = prefsKey;
|
|
14753
14828
|
const viewKey = `${resourceKey}::${resolvedLayoutPreferenceType}::${currentViewName}`;
|
|
14754
14829
|
if (layoutPrefsResourceRef.current !== viewKey) {
|
|
14755
14830
|
layoutPrefsLoadedRef.current = false;
|
|
@@ -14763,7 +14838,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14763
14838
|
let cancelled = false;
|
|
14764
14839
|
const applyPrefs = (prefs) => {
|
|
14765
14840
|
if (!prefs || typeof prefs !== "object") return false;
|
|
14766
|
-
if ("listVisible" in prefs) setListVisible(Boolean(prefs.listVisible));
|
|
14841
|
+
if ("listVisible" in prefs && defaultListVisible !== false) setListVisible(Boolean(prefs.listVisible));
|
|
14767
14842
|
if ("analyzeOpen" in prefs) setAnalyzeOpen(Boolean(prefs.analyzeOpen));
|
|
14768
14843
|
if ("isAnalyzeVertical" in prefs) setIsAnalyzeVertical(Boolean(prefs.isAnalyzeVertical));
|
|
14769
14844
|
if ("isAnalyzeFirst" in prefs) setIsAnalyzeFirst(Boolean(prefs.isAnalyzeFirst));
|
|
@@ -14831,7 +14906,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
14831
14906
|
return () => {
|
|
14832
14907
|
cancelled = true;
|
|
14833
14908
|
};
|
|
14834
|
-
}, [apiUrl, currentViewName, resolvedLayoutPreferenceType, model.name, model.resource, allModels]);
|
|
14909
|
+
}, [apiUrl, currentViewName, resolvedLayoutPreferenceType, model.name, model.resource, allModels, preferencesResourceOverride]);
|
|
14835
14910
|
const fetchAllRows = useCallback(async () => {
|
|
14836
14911
|
setIsAllRowsLoading(true);
|
|
14837
14912
|
setAllRowsError(null);
|
|
@@ -15517,6 +15592,17 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
15517
15592
|
body: JSON.stringify(clonePayload)
|
|
15518
15593
|
});
|
|
15519
15594
|
if (!resp.ok) throw new Error(`${_32("Clone failed for record")} ${id}`);
|
|
15595
|
+
} else if (actionKey === "__pin__") {
|
|
15596
|
+
await authenticatedFetch(`${apiUrl}/dashboard/pinned-records`, {
|
|
15597
|
+
method: "POST",
|
|
15598
|
+
headers: { "Content-Type": "application/json" },
|
|
15599
|
+
body: JSON.stringify({ resource, record_id: String(id) })
|
|
15600
|
+
});
|
|
15601
|
+
} else if (actionKey === "__unpin__") {
|
|
15602
|
+
await authenticatedFetch(
|
|
15603
|
+
`${apiUrl}/dashboard/pinned-records/${encodeURIComponent(resource)}/${encodeURIComponent(String(id))}`,
|
|
15604
|
+
{ method: "DELETE" }
|
|
15605
|
+
);
|
|
15520
15606
|
} else {
|
|
15521
15607
|
const customAction = bulkActions?.find((a) => a.key === actionKey);
|
|
15522
15608
|
if (customAction) await customAction.onExecuteOne(record);
|
|
@@ -15604,6 +15690,8 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
|
|
|
15604
15690
|
if (bulkActions && bulkActions.length > 0) {
|
|
15605
15691
|
bulkActions.forEach((a) => opts.push({ label: _32(a.label), value: a.key }));
|
|
15606
15692
|
}
|
|
15693
|
+
opts.push({ label: _32("Pin selected"), value: "__pin__" });
|
|
15694
|
+
opts.push({ label: _32("Unpin selected"), value: "__unpin__" });
|
|
15607
15695
|
if (canBulkDelete) {
|
|
15608
15696
|
opts.push({ label: _32("Delete selected"), value: "__delete__" });
|
|
15609
15697
|
}
|
|
@@ -17580,7 +17668,7 @@ var MultiPaneLayout = ({ children }) => {
|
|
|
17580
17668
|
[openDetail]
|
|
17581
17669
|
);
|
|
17582
17670
|
const detailPaneContexts = useMemo(
|
|
17583
|
-
() => panes.map((
|
|
17671
|
+
() => panes.map((_39, idx) => ({
|
|
17584
17672
|
isInMultiPane: true,
|
|
17585
17673
|
paneIndex: idx + 1,
|
|
17586
17674
|
openDetail: (resource, id) => openDetail(idx + 1, resource, id)
|
|
@@ -17990,9 +18078,6 @@ httpClient.interceptors.request.use((config) => {
|
|
|
17990
18078
|
}
|
|
17991
18079
|
return config;
|
|
17992
18080
|
});
|
|
17993
|
-
|
|
17994
|
-
// src/providers/constants.ts
|
|
17995
|
-
var API_URL3 = "/api";
|
|
17996
18081
|
var API_BASE_URL = "/api";
|
|
17997
18082
|
var ColorModeContextProvider = ({
|
|
17998
18083
|
children
|
|
@@ -18162,6 +18247,773 @@ var LoginPage = ({ appTitle = "VeloIQ", logo }) => {
|
|
|
18162
18247
|
}
|
|
18163
18248
|
);
|
|
18164
18249
|
};
|
|
18250
|
+
function useDashboardConfig() {
|
|
18251
|
+
const apiUrl = useApiUrl();
|
|
18252
|
+
const [config, setConfig] = useState(null);
|
|
18253
|
+
const [enabled, setEnabled] = useState(false);
|
|
18254
|
+
const [loading, setLoading] = useState(true);
|
|
18255
|
+
const load = useCallback(async () => {
|
|
18256
|
+
setLoading(true);
|
|
18257
|
+
try {
|
|
18258
|
+
const res = await authenticatedFetch(`${apiUrl}/dashboard/config`);
|
|
18259
|
+
if (!res.ok) {
|
|
18260
|
+
setLoading(false);
|
|
18261
|
+
return;
|
|
18262
|
+
}
|
|
18263
|
+
const data = await res.json();
|
|
18264
|
+
setEnabled(Boolean(data.enabled));
|
|
18265
|
+
if (data.enabled && data.dashboard) {
|
|
18266
|
+
setConfig(data.dashboard);
|
|
18267
|
+
}
|
|
18268
|
+
} catch {
|
|
18269
|
+
} finally {
|
|
18270
|
+
setLoading(false);
|
|
18271
|
+
}
|
|
18272
|
+
}, [apiUrl]);
|
|
18273
|
+
useEffect(() => {
|
|
18274
|
+
load();
|
|
18275
|
+
}, [load]);
|
|
18276
|
+
const save = useCallback(async (next) => {
|
|
18277
|
+
setConfig(next);
|
|
18278
|
+
try {
|
|
18279
|
+
await authenticatedFetch(`${apiUrl}/dashboard/config`, {
|
|
18280
|
+
method: "PUT",
|
|
18281
|
+
headers: { "Content-Type": "application/json" },
|
|
18282
|
+
body: JSON.stringify({ dashboard: next })
|
|
18283
|
+
});
|
|
18284
|
+
} catch {
|
|
18285
|
+
}
|
|
18286
|
+
}, [apiUrl]);
|
|
18287
|
+
return { config, enabled, loading, save, reload: load };
|
|
18288
|
+
}
|
|
18289
|
+
var { Text } = Typography;
|
|
18290
|
+
var VIEW_TYPE_OPTIONS = [
|
|
18291
|
+
{ label: "Default (from model schema)", value: "" },
|
|
18292
|
+
{ label: "Table", value: "table" },
|
|
18293
|
+
{ label: "Gallery", value: "gallery" },
|
|
18294
|
+
{ label: "Calendar", value: "calendar" },
|
|
18295
|
+
{ label: "Totals / Details", value: "totals-details" }
|
|
18296
|
+
];
|
|
18297
|
+
var nextGridPosition = (cells) => {
|
|
18298
|
+
if (!cells.length) return { row: 0, col: 0 };
|
|
18299
|
+
const maxRow = Math.max(...cells.map((c) => c.row));
|
|
18300
|
+
const lastRowCells = cells.filter((c) => c.row === maxRow);
|
|
18301
|
+
if (lastRowCells.length < 2) return { row: maxRow, col: lastRowCells.length };
|
|
18302
|
+
return { row: maxRow + 1, col: 0 };
|
|
18303
|
+
};
|
|
18304
|
+
var CellConfigDrawer = ({ open, cell, tabId, config, onClose, onSave }) => {
|
|
18305
|
+
const [form] = Form.useForm();
|
|
18306
|
+
useEffect(() => {
|
|
18307
|
+
if (!cell || !tabId) return;
|
|
18308
|
+
const tab = config.tabs.find((t) => t.id === tabId);
|
|
18309
|
+
form.setFieldsValue({
|
|
18310
|
+
tabName: tab?.name ?? "",
|
|
18311
|
+
row: cell.row + 1,
|
|
18312
|
+
col: cell.col + 1,
|
|
18313
|
+
view_type: cell.view_type ?? "",
|
|
18314
|
+
html_style: cell.html_style ?? "",
|
|
18315
|
+
min_width: cell.min_width ?? "",
|
|
18316
|
+
max_width: cell.max_width ?? "",
|
|
18317
|
+
min_height: cell.min_height ?? "",
|
|
18318
|
+
max_height: cell.max_height ?? ""
|
|
18319
|
+
});
|
|
18320
|
+
}, [cell, tabId, config, form]);
|
|
18321
|
+
const handleSave = () => {
|
|
18322
|
+
if (!cell || !tabId) return;
|
|
18323
|
+
const values = form.getFieldsValue();
|
|
18324
|
+
const newTabName = (values.tabName || "").trim() || config.tabs.find((t) => t.id === tabId)?.name || "";
|
|
18325
|
+
const updatedCell = {
|
|
18326
|
+
...cell,
|
|
18327
|
+
row: Math.max(0, (values.row ?? 1) - 1),
|
|
18328
|
+
col: Math.max(0, (values.col ?? 1) - 1),
|
|
18329
|
+
view_type: values.view_type || null,
|
|
18330
|
+
html_style: values.html_style ?? "",
|
|
18331
|
+
min_width: values.min_width || null,
|
|
18332
|
+
max_width: values.max_width || null,
|
|
18333
|
+
min_height: values.min_height || null,
|
|
18334
|
+
max_height: values.max_height || null
|
|
18335
|
+
};
|
|
18336
|
+
const currentTab = config.tabs.find((t) => t.id === tabId);
|
|
18337
|
+
const nameUnchanged = currentTab?.name.trim().toLowerCase() === newTabName.toLowerCase();
|
|
18338
|
+
const targetTab = !nameUnchanged ? config.tabs.find((t) => t.id !== tabId && t.name.trim().toLowerCase() === newTabName.toLowerCase()) : void 0;
|
|
18339
|
+
let nextTabs;
|
|
18340
|
+
if (nameUnchanged) {
|
|
18341
|
+
nextTabs = config.tabs.map((tab) => {
|
|
18342
|
+
if (tab.id !== tabId) return tab;
|
|
18343
|
+
return { ...tab, cells: tab.cells.map((c) => c.id === cell.id ? updatedCell : c) };
|
|
18344
|
+
});
|
|
18345
|
+
} else if (targetTab) {
|
|
18346
|
+
const { row, col } = nextGridPosition(targetTab.cells);
|
|
18347
|
+
const repositionedCell = { ...updatedCell, row, col };
|
|
18348
|
+
nextTabs = config.tabs.map((tab) => {
|
|
18349
|
+
if (tab.id === tabId) {
|
|
18350
|
+
return { ...tab, cells: tab.cells.filter((c) => c.id !== cell.id) };
|
|
18351
|
+
}
|
|
18352
|
+
if (tab.id === targetTab.id) {
|
|
18353
|
+
return { ...tab, cells: [...tab.cells, repositionedCell] };
|
|
18354
|
+
}
|
|
18355
|
+
return tab;
|
|
18356
|
+
}).filter((tab) => tab.cells.length > 0);
|
|
18357
|
+
} else {
|
|
18358
|
+
const { row, col } = nextGridPosition([]);
|
|
18359
|
+
const repositionedCell = { ...updatedCell, row, col };
|
|
18360
|
+
const newTab = {
|
|
18361
|
+
id: crypto.randomUUID(),
|
|
18362
|
+
name: newTabName,
|
|
18363
|
+
module: currentTab?.module ?? "dashboard",
|
|
18364
|
+
cells: [repositionedCell]
|
|
18365
|
+
};
|
|
18366
|
+
nextTabs = [
|
|
18367
|
+
...config.tabs.map((tab) => {
|
|
18368
|
+
if (tab.id !== tabId) return tab;
|
|
18369
|
+
return { ...tab, cells: tab.cells.filter((c) => c.id !== cell.id) };
|
|
18370
|
+
}).filter((tab) => tab.cells.length > 0),
|
|
18371
|
+
newTab
|
|
18372
|
+
];
|
|
18373
|
+
}
|
|
18374
|
+
onSave({ ...config, tabs: nextTabs });
|
|
18375
|
+
onClose();
|
|
18376
|
+
};
|
|
18377
|
+
return /* @__PURE__ */ jsx(
|
|
18378
|
+
Drawer,
|
|
18379
|
+
{
|
|
18380
|
+
title: `Configure cell: ${cell?.model ?? ""}`,
|
|
18381
|
+
placement: "right",
|
|
18382
|
+
width: 380,
|
|
18383
|
+
open,
|
|
18384
|
+
onClose,
|
|
18385
|
+
footer: /* @__PURE__ */ jsxs(Space, { style: { justifyContent: "flex-end", width: "100%", display: "flex" }, children: [
|
|
18386
|
+
/* @__PURE__ */ jsx(Button, { onClick: onClose, children: "Cancel" }),
|
|
18387
|
+
/* @__PURE__ */ jsx(Button, { type: "primary", onClick: handleSave, children: "Save" })
|
|
18388
|
+
] }),
|
|
18389
|
+
children: /* @__PURE__ */ jsxs(Form, { form, layout: "vertical", size: "small", children: [
|
|
18390
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "left", children: "Tab" }),
|
|
18391
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "tabName", label: "Tab name", children: /* @__PURE__ */ jsx(Input, {}) }),
|
|
18392
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "left", children: "Position" }),
|
|
18393
|
+
/* @__PURE__ */ jsxs(Space, { children: [
|
|
18394
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "row", label: "Row", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(InputNumber, { min: 1, style: { width: 80 } }) }),
|
|
18395
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "col", label: "Column", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(InputNumber, { min: 1, style: { width: 80 } }) })
|
|
18396
|
+
] }),
|
|
18397
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "left", children: "View" }),
|
|
18398
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "view_type", label: "View type", children: /* @__PURE__ */ jsx(Select, { options: VIEW_TYPE_OPTIONS }) }),
|
|
18399
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "left", children: "Size" }),
|
|
18400
|
+
/* @__PURE__ */ jsxs(Space, { wrap: true, children: [
|
|
18401
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "min_width", label: "Min width", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(Input, { placeholder: "e.g. 320px", style: { width: 130 } }) }),
|
|
18402
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "max_width", label: "Max width", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(Input, { placeholder: "e.g. 800px", style: { width: 130 } }) })
|
|
18403
|
+
] }),
|
|
18404
|
+
/* @__PURE__ */ jsxs(Space, { wrap: true, style: { marginTop: 8 }, children: [
|
|
18405
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "min_height", label: "Min height", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(Input, { placeholder: "e.g. 300px", style: { width: 130 } }) }),
|
|
18406
|
+
/* @__PURE__ */ jsx(Form.Item, { name: "max_height", label: "Max height", style: { marginBottom: 0 }, children: /* @__PURE__ */ jsx(Input, { placeholder: "e.g. 600px", style: { width: 130 } }) })
|
|
18407
|
+
] }),
|
|
18408
|
+
/* @__PURE__ */ jsx(Divider, { orientation: "left", children: "Style" }),
|
|
18409
|
+
/* @__PURE__ */ jsx(
|
|
18410
|
+
Form.Item,
|
|
18411
|
+
{
|
|
18412
|
+
name: "html_style",
|
|
18413
|
+
label: /* @__PURE__ */ jsxs(Text, { children: [
|
|
18414
|
+
"HTML style ",
|
|
18415
|
+
/* @__PURE__ */ jsx(Text, { type: "secondary", children: "(inline CSS)" })
|
|
18416
|
+
] }),
|
|
18417
|
+
children: /* @__PURE__ */ jsx(
|
|
18418
|
+
Input.TextArea,
|
|
18419
|
+
{
|
|
18420
|
+
rows: 4,
|
|
18421
|
+
placeholder: "e.g. background-color: #f0f4ff; border-radius: 8px;",
|
|
18422
|
+
style: { fontFamily: "monospace", fontSize: 12 }
|
|
18423
|
+
}
|
|
18424
|
+
)
|
|
18425
|
+
}
|
|
18426
|
+
)
|
|
18427
|
+
] })
|
|
18428
|
+
}
|
|
18429
|
+
);
|
|
18430
|
+
};
|
|
18431
|
+
var DashboardGridCell = ({ cell, allModels, isMaximized, isMinimized, onConfigure, onMaximize, onMinimize }) => {
|
|
18432
|
+
const { token } = theme.useToken();
|
|
18433
|
+
const model = findModelByName(allModels, cell.model);
|
|
18434
|
+
const cellStyle = {
|
|
18435
|
+
border: `1px solid ${token.colorBorderSecondary}`,
|
|
18436
|
+
borderRadius: token.borderRadiusLG,
|
|
18437
|
+
overflow: "hidden",
|
|
18438
|
+
display: "flex",
|
|
18439
|
+
flexDirection: "column",
|
|
18440
|
+
background: token.colorBgContainer,
|
|
18441
|
+
...cell.min_width ? { minWidth: cell.min_width } : {},
|
|
18442
|
+
...cell.max_width ? { maxWidth: cell.max_width } : {},
|
|
18443
|
+
...cell.min_height ? { minHeight: cell.min_height } : {},
|
|
18444
|
+
...cell.max_height ? { maxHeight: cell.max_height } : {},
|
|
18445
|
+
...cell.html_style ? parseInlineStyle3(cell.html_style) : {},
|
|
18446
|
+
...isMaximized ? { gridColumn: "1 / -1" } : {},
|
|
18447
|
+
...isMinimized ? { minHeight: 0 } : {}
|
|
18448
|
+
};
|
|
18449
|
+
const toolbarStyle = {
|
|
18450
|
+
display: "flex",
|
|
18451
|
+
alignItems: "center",
|
|
18452
|
+
justifyContent: "space-between",
|
|
18453
|
+
padding: "2px 8px",
|
|
18454
|
+
gap: 2,
|
|
18455
|
+
borderBottom: `1px solid ${token.colorBorderSecondary}`,
|
|
18456
|
+
background: token.colorBgContainer,
|
|
18457
|
+
flexShrink: 0,
|
|
18458
|
+
minHeight: 32,
|
|
18459
|
+
position: "relative"
|
|
18460
|
+
};
|
|
18461
|
+
const resource = model?.resource || cell.model;
|
|
18462
|
+
const cellTitle = model?.label || cell.model;
|
|
18463
|
+
return /* @__PURE__ */ jsxs("div", { style: cellStyle, className: "jm-dashboard-cell", children: [
|
|
18464
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
18465
|
+
.jm-dashboard-cell .jm-cell-actions { opacity: 0; transition: opacity 0.15s; }
|
|
18466
|
+
.jm-dashboard-cell:hover .jm-cell-actions { opacity: 1; }
|
|
18467
|
+
` }),
|
|
18468
|
+
/* @__PURE__ */ jsxs("div", { style: toolbarStyle, children: [
|
|
18469
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
18470
|
+
fontSize: token.fontSizeSM,
|
|
18471
|
+
fontWeight: token.fontWeightStrong,
|
|
18472
|
+
color: token.colorText,
|
|
18473
|
+
paddingLeft: 4,
|
|
18474
|
+
overflow: "hidden",
|
|
18475
|
+
textOverflow: "ellipsis",
|
|
18476
|
+
whiteSpace: "nowrap"
|
|
18477
|
+
}, children: cellTitle }),
|
|
18478
|
+
/* @__PURE__ */ jsxs("div", { className: "jm-cell-actions", style: { display: "flex", alignItems: "center", gap: 2 }, children: [
|
|
18479
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Configure cell", children: /* @__PURE__ */ jsx(
|
|
18480
|
+
Button,
|
|
18481
|
+
{
|
|
18482
|
+
type: "text",
|
|
18483
|
+
size: "small",
|
|
18484
|
+
icon: /* @__PURE__ */ jsx(SettingOutlined, { style: { fontSize: 11 } }),
|
|
18485
|
+
onClick: onConfigure,
|
|
18486
|
+
style: { color: token.colorTextTertiary, padding: "0 4px", height: 22, minWidth: 22 }
|
|
18487
|
+
}
|
|
18488
|
+
) }),
|
|
18489
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Open full page", children: /* @__PURE__ */ jsx(Link, { to: `/${resource}`, style: { color: token.colorTextTertiary, display: "flex", alignItems: "center", padding: "0 4px" }, children: /* @__PURE__ */ jsx(LinkOutlined, { style: { fontSize: 11 } }) }) }),
|
|
18490
|
+
/* @__PURE__ */ jsx(Tooltip, { title: isMaximized ? "Restore" : "Maximize", children: /* @__PURE__ */ jsx(
|
|
18491
|
+
Button,
|
|
18492
|
+
{
|
|
18493
|
+
type: "text",
|
|
18494
|
+
size: "small",
|
|
18495
|
+
icon: /* @__PURE__ */ jsx(FullscreenOutlined, { style: { fontSize: 11 } }),
|
|
18496
|
+
onClick: onMaximize,
|
|
18497
|
+
style: { color: token.colorTextTertiary, padding: "0 4px", height: 22, minWidth: 22 }
|
|
18498
|
+
}
|
|
18499
|
+
) }),
|
|
18500
|
+
/* @__PURE__ */ jsx(Tooltip, { title: isMinimized ? "Restore" : "Minimize", children: /* @__PURE__ */ jsx(
|
|
18501
|
+
Button,
|
|
18502
|
+
{
|
|
18503
|
+
type: "text",
|
|
18504
|
+
size: "small",
|
|
18505
|
+
icon: /* @__PURE__ */ jsx(MinusSquareOutlined, { style: { fontSize: 11 } }),
|
|
18506
|
+
onClick: onMinimize,
|
|
18507
|
+
style: { color: token.colorTextTertiary, padding: "0 4px", height: 22, minWidth: 22 }
|
|
18508
|
+
}
|
|
18509
|
+
) })
|
|
18510
|
+
] })
|
|
18511
|
+
] }),
|
|
18512
|
+
!isMinimized && /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto", minHeight: 0 }, children: model ? /* @__PURE__ */ jsx(
|
|
18513
|
+
DynamicList,
|
|
18514
|
+
{
|
|
18515
|
+
model,
|
|
18516
|
+
allModels,
|
|
18517
|
+
isEmbedded: true,
|
|
18518
|
+
preferencesResourceOverride: `dashboard:${resource}`,
|
|
18519
|
+
defaultListVisible: false,
|
|
18520
|
+
listViewType: cell.view_type ? cell.view_type : model.listViewType
|
|
18521
|
+
}
|
|
18522
|
+
) : /* @__PURE__ */ jsx(
|
|
18523
|
+
Empty,
|
|
18524
|
+
{
|
|
18525
|
+
description: `Model "${cell.model}" not found`,
|
|
18526
|
+
style: { padding: 24 },
|
|
18527
|
+
image: Empty.PRESENTED_IMAGE_SIMPLE
|
|
18528
|
+
}
|
|
18529
|
+
) })
|
|
18530
|
+
] });
|
|
18531
|
+
};
|
|
18532
|
+
var DashboardTabContent = ({ tab, allModels, maximizedCellId, minimizedCellIds, onMaximize, onMinimize, onConfigure }) => {
|
|
18533
|
+
const cells = tab.cells;
|
|
18534
|
+
const numCols = useMemo(() => {
|
|
18535
|
+
if (!cells.length) return 2;
|
|
18536
|
+
return Math.max(...cells.map((c) => c.col)) + 1;
|
|
18537
|
+
}, [cells]);
|
|
18538
|
+
const numRows = useMemo(() => {
|
|
18539
|
+
if (!cells.length) return 1;
|
|
18540
|
+
return Math.max(...cells.map((c) => c.row)) + 1;
|
|
18541
|
+
}, [cells]);
|
|
18542
|
+
const visibleCells = maximizedCellId ? cells.filter((c) => c.id === maximizedCellId) : cells;
|
|
18543
|
+
const gridStyle = {
|
|
18544
|
+
display: "grid",
|
|
18545
|
+
gridTemplateColumns: maximizedCellId ? "1fr" : `repeat(${numCols}, 1fr)`,
|
|
18546
|
+
gridTemplateRows: maximizedCellId ? "1fr" : `repeat(${numRows}, minmax(320px, auto))`,
|
|
18547
|
+
gap: 12,
|
|
18548
|
+
padding: 12,
|
|
18549
|
+
height: "100%",
|
|
18550
|
+
boxSizing: "border-box"
|
|
18551
|
+
};
|
|
18552
|
+
if (!cells.length) {
|
|
18553
|
+
return /* @__PURE__ */ jsx(Empty, { description: "No models in this tab", style: { padding: 48 } });
|
|
18554
|
+
}
|
|
18555
|
+
return /* @__PURE__ */ jsx("div", { style: gridStyle, children: visibleCells.map((cell) => /* @__PURE__ */ jsx(
|
|
18556
|
+
"div",
|
|
18557
|
+
{
|
|
18558
|
+
style: {
|
|
18559
|
+
gridColumn: maximizedCellId ? "1 / -1" : `${cell.col + 1}`,
|
|
18560
|
+
gridRow: maximizedCellId ? "1 / -1" : `${cell.row + 1}`
|
|
18561
|
+
},
|
|
18562
|
+
children: /* @__PURE__ */ jsx(
|
|
18563
|
+
DashboardGridCell,
|
|
18564
|
+
{
|
|
18565
|
+
cell,
|
|
18566
|
+
allModels,
|
|
18567
|
+
isMaximized: maximizedCellId === cell.id,
|
|
18568
|
+
isMinimized: minimizedCellIds.has(cell.id),
|
|
18569
|
+
onConfigure: () => onConfigure(cell),
|
|
18570
|
+
onMaximize: () => onMaximize(cell.id),
|
|
18571
|
+
onMinimize: () => onMinimize(cell.id)
|
|
18572
|
+
}
|
|
18573
|
+
)
|
|
18574
|
+
},
|
|
18575
|
+
cell.id
|
|
18576
|
+
)) });
|
|
18577
|
+
};
|
|
18578
|
+
var ViewsGrid = ({ config, allModels, onConfigChange }) => {
|
|
18579
|
+
const [maximizedCellId, setMaximizedCellId] = useState(null);
|
|
18580
|
+
const [minimizedCellIds, setMinimizedCellIds] = useState(/* @__PURE__ */ new Set());
|
|
18581
|
+
const [drawerSelection, setDrawerSelection] = useState(null);
|
|
18582
|
+
const handleMaximize = useCallback((cellId) => {
|
|
18583
|
+
setMaximizedCellId((prev) => prev === cellId ? null : cellId);
|
|
18584
|
+
}, []);
|
|
18585
|
+
const handleMinimize = useCallback((cellId) => {
|
|
18586
|
+
setMinimizedCellIds((prev) => {
|
|
18587
|
+
const next = new Set(prev);
|
|
18588
|
+
if (next.has(cellId)) {
|
|
18589
|
+
next.delete(cellId);
|
|
18590
|
+
} else {
|
|
18591
|
+
next.add(cellId);
|
|
18592
|
+
}
|
|
18593
|
+
return next;
|
|
18594
|
+
});
|
|
18595
|
+
}, []);
|
|
18596
|
+
const handleOpenDrawer = useCallback((tabId, cell) => {
|
|
18597
|
+
setDrawerSelection({ tabId, cell });
|
|
18598
|
+
}, []);
|
|
18599
|
+
const handleSaveConfig = useCallback((nextConfig) => {
|
|
18600
|
+
onConfigChange(nextConfig);
|
|
18601
|
+
setDrawerSelection(null);
|
|
18602
|
+
}, [onConfigChange]);
|
|
18603
|
+
const tabItems = useMemo(
|
|
18604
|
+
() => config.tabs.map((tab) => ({
|
|
18605
|
+
key: tab.id,
|
|
18606
|
+
label: tab.name,
|
|
18607
|
+
children: /* @__PURE__ */ jsx(
|
|
18608
|
+
DashboardTabContent,
|
|
18609
|
+
{
|
|
18610
|
+
tab,
|
|
18611
|
+
allModels,
|
|
18612
|
+
maximizedCellId,
|
|
18613
|
+
minimizedCellIds,
|
|
18614
|
+
onMaximize: handleMaximize,
|
|
18615
|
+
onMinimize: handleMinimize,
|
|
18616
|
+
onConfigure: (cell) => handleOpenDrawer(tab.id, cell)
|
|
18617
|
+
}
|
|
18618
|
+
)
|
|
18619
|
+
})),
|
|
18620
|
+
[config.tabs, allModels, maximizedCellId, minimizedCellIds, handleMaximize, handleMinimize, handleOpenDrawer]
|
|
18621
|
+
);
|
|
18622
|
+
if (!config.tabs.length) {
|
|
18623
|
+
return /* @__PURE__ */ jsx(Empty, { description: "No tabs configured. Run veloiq add-dashboard to add models.", style: { padding: 48 } });
|
|
18624
|
+
}
|
|
18625
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
18626
|
+
/* @__PURE__ */ jsx(
|
|
18627
|
+
Tabs,
|
|
18628
|
+
{
|
|
18629
|
+
items: tabItems,
|
|
18630
|
+
onChange: () => {
|
|
18631
|
+
setMaximizedCellId(null);
|
|
18632
|
+
setMinimizedCellIds(/* @__PURE__ */ new Set());
|
|
18633
|
+
},
|
|
18634
|
+
style: { height: "100%" },
|
|
18635
|
+
tabBarStyle: { paddingLeft: 12, marginBottom: 0 }
|
|
18636
|
+
}
|
|
18637
|
+
),
|
|
18638
|
+
/* @__PURE__ */ jsx(
|
|
18639
|
+
CellConfigDrawer,
|
|
18640
|
+
{
|
|
18641
|
+
open: Boolean(drawerSelection),
|
|
18642
|
+
cell: drawerSelection?.cell ?? null,
|
|
18643
|
+
tabId: drawerSelection?.tabId ?? null,
|
|
18644
|
+
config,
|
|
18645
|
+
onClose: () => setDrawerSelection(null),
|
|
18646
|
+
onSave: handleSaveConfig
|
|
18647
|
+
}
|
|
18648
|
+
)
|
|
18649
|
+
] });
|
|
18650
|
+
};
|
|
18651
|
+
function parseInlineStyle3(cssText) {
|
|
18652
|
+
const result = {};
|
|
18653
|
+
cssText.split(";").forEach((declaration) => {
|
|
18654
|
+
const idx = declaration.indexOf(":");
|
|
18655
|
+
if (idx < 0) return;
|
|
18656
|
+
const prop = declaration.slice(0, idx).trim();
|
|
18657
|
+
const value = declaration.slice(idx + 1).trim();
|
|
18658
|
+
if (!prop || !value) return;
|
|
18659
|
+
const camel = prop.replace(/-([a-z])/g, (_39, c) => c.toUpperCase());
|
|
18660
|
+
result[camel] = value;
|
|
18661
|
+
});
|
|
18662
|
+
return result;
|
|
18663
|
+
}
|
|
18664
|
+
function useRecentActivity(days) {
|
|
18665
|
+
const [data, setData] = useState(null);
|
|
18666
|
+
const [loading, setLoading] = useState(true);
|
|
18667
|
+
const load = useCallback(async () => {
|
|
18668
|
+
setLoading(true);
|
|
18669
|
+
try {
|
|
18670
|
+
const params = days !== void 0 ? `?days=${days}` : "";
|
|
18671
|
+
const res = await authenticatedFetch(`${API_URL3}/dashboard/recent-activity${params}`);
|
|
18672
|
+
if (res.ok) setData(await res.json());
|
|
18673
|
+
} catch {
|
|
18674
|
+
} finally {
|
|
18675
|
+
setLoading(false);
|
|
18676
|
+
}
|
|
18677
|
+
}, [days]);
|
|
18678
|
+
useEffect(() => {
|
|
18679
|
+
load();
|
|
18680
|
+
}, [load]);
|
|
18681
|
+
return { data, loading, reload: load };
|
|
18682
|
+
}
|
|
18683
|
+
var { Text: Text2, Title: Title9 } = Typography;
|
|
18684
|
+
function relativeTime(iso) {
|
|
18685
|
+
if (!iso) return "";
|
|
18686
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
18687
|
+
const mins = Math.floor(diff / 6e4);
|
|
18688
|
+
if (mins < 1) return "just now";
|
|
18689
|
+
if (mins < 60) return `${mins}m ago`;
|
|
18690
|
+
const hrs = Math.floor(mins / 60);
|
|
18691
|
+
if (hrs < 24) return `${hrs}h ago`;
|
|
18692
|
+
const days = Math.floor(hrs / 24);
|
|
18693
|
+
if (days < 30) return `${days}d ago`;
|
|
18694
|
+
return new Date(iso).toLocaleDateString();
|
|
18695
|
+
}
|
|
18696
|
+
var RecentActivityPanel = () => {
|
|
18697
|
+
const { token } = theme.useToken();
|
|
18698
|
+
const allModels = useAllModels();
|
|
18699
|
+
const [days, setDays] = useState(30);
|
|
18700
|
+
const { data, loading, reload } = useRecentActivity(days);
|
|
18701
|
+
const groups = data?.groups ?? [];
|
|
18702
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "16px 0" }, children: [
|
|
18703
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 20, paddingLeft: 4 }, children: [
|
|
18704
|
+
/* @__PURE__ */ jsx(Text2, { type: "secondary", children: "Show activity from the last" }),
|
|
18705
|
+
/* @__PURE__ */ jsx(
|
|
18706
|
+
InputNumber,
|
|
18707
|
+
{
|
|
18708
|
+
min: 1,
|
|
18709
|
+
max: 365,
|
|
18710
|
+
value: days,
|
|
18711
|
+
onChange: (v) => v && setDays(v),
|
|
18712
|
+
style: { width: 72 },
|
|
18713
|
+
size: "small"
|
|
18714
|
+
}
|
|
18715
|
+
),
|
|
18716
|
+
/* @__PURE__ */ jsx(Text2, { type: "secondary", children: "days" }),
|
|
18717
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Refresh", children: /* @__PURE__ */ jsx(
|
|
18718
|
+
ReloadOutlined,
|
|
18719
|
+
{
|
|
18720
|
+
style: { color: token.colorTextTertiary, cursor: "pointer", fontSize: 13 },
|
|
18721
|
+
onClick: reload
|
|
18722
|
+
}
|
|
18723
|
+
) }),
|
|
18724
|
+
data && /* @__PURE__ */ jsxs(Text2, { type: "secondary", style: { fontSize: 12 }, children: [
|
|
18725
|
+
groups.reduce((n, g) => n + g.records.length, 0),
|
|
18726
|
+
" records across ",
|
|
18727
|
+
groups.length,
|
|
18728
|
+
" models"
|
|
18729
|
+
] })
|
|
18730
|
+
] }),
|
|
18731
|
+
loading ? /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", padding: 48 }, children: /* @__PURE__ */ jsx(Spin, {}) }) : groups.length === 0 ? /* @__PURE__ */ jsx(
|
|
18732
|
+
Empty,
|
|
18733
|
+
{
|
|
18734
|
+
description: `No activity in the last ${days} days`,
|
|
18735
|
+
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
|
18736
|
+
style: { padding: 48 }
|
|
18737
|
+
}
|
|
18738
|
+
) : /* @__PURE__ */ jsx(Space, { direction: "vertical", size: 24, style: { width: "100%" }, children: groups.map((group) => {
|
|
18739
|
+
const model = findModelByName(allModels, group.resource);
|
|
18740
|
+
const tone = getModelTone(model?.name ?? group.resource);
|
|
18741
|
+
const label = model?.label ?? group.model_name;
|
|
18742
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
18743
|
+
/* @__PURE__ */ jsxs("div", { style: {
|
|
18744
|
+
display: "flex",
|
|
18745
|
+
alignItems: "center",
|
|
18746
|
+
gap: 8,
|
|
18747
|
+
marginBottom: 6,
|
|
18748
|
+
paddingBottom: 6,
|
|
18749
|
+
borderBottom: `2px solid ${tone.solid}40`
|
|
18750
|
+
}, children: [
|
|
18751
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
18752
|
+
width: 10,
|
|
18753
|
+
height: 10,
|
|
18754
|
+
borderRadius: "50%",
|
|
18755
|
+
background: tone.solid,
|
|
18756
|
+
flexShrink: 0
|
|
18757
|
+
} }),
|
|
18758
|
+
/* @__PURE__ */ jsx(Title9, { level: 5, style: { margin: 0, color: tone.text }, children: label }),
|
|
18759
|
+
/* @__PURE__ */ jsx(Tag, { color: tone.solid, style: { marginLeft: "auto", fontSize: 11 }, children: group.records.length })
|
|
18760
|
+
] }),
|
|
18761
|
+
/* @__PURE__ */ jsx(
|
|
18762
|
+
List$1,
|
|
18763
|
+
{
|
|
18764
|
+
size: "small",
|
|
18765
|
+
dataSource: group.records,
|
|
18766
|
+
renderItem: (rec) => {
|
|
18767
|
+
const timestamp = rec.updated_at || rec.created_at;
|
|
18768
|
+
const isNew = rec.created_at === rec.updated_at;
|
|
18769
|
+
return /* @__PURE__ */ jsxs(
|
|
18770
|
+
List$1.Item,
|
|
18771
|
+
{
|
|
18772
|
+
style: {
|
|
18773
|
+
padding: "4px 8px",
|
|
18774
|
+
borderRadius: token.borderRadius,
|
|
18775
|
+
transition: "background 0.15s"
|
|
18776
|
+
},
|
|
18777
|
+
className: "jm-activity-row",
|
|
18778
|
+
children: [
|
|
18779
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
18780
|
+
.jm-activity-row:hover { background: ${token.colorFillAlter}; }
|
|
18781
|
+
` }),
|
|
18782
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, width: "100%" }, children: [
|
|
18783
|
+
/* @__PURE__ */ jsx(ClockCircleOutlined, { style: { color: token.colorTextTertiary, fontSize: 11, flexShrink: 0 } }),
|
|
18784
|
+
/* @__PURE__ */ jsx(
|
|
18785
|
+
Link,
|
|
18786
|
+
{
|
|
18787
|
+
to: `/${group.resource}/show/${rec.id}`,
|
|
18788
|
+
style: { flex: 1, color: token.colorText, fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
18789
|
+
children: rec._label || `#${rec.id}`
|
|
18790
|
+
}
|
|
18791
|
+
),
|
|
18792
|
+
isNew && /* @__PURE__ */ jsx(Tag, { color: "green", style: { fontSize: 10, padding: "0 4px", lineHeight: "16px" }, children: "new" }),
|
|
18793
|
+
/* @__PURE__ */ jsx(Text2, { type: "secondary", style: { fontSize: 11, flexShrink: 0 }, children: relativeTime(timestamp) })
|
|
18794
|
+
] })
|
|
18795
|
+
]
|
|
18796
|
+
}
|
|
18797
|
+
);
|
|
18798
|
+
}
|
|
18799
|
+
}
|
|
18800
|
+
)
|
|
18801
|
+
] }, group.resource);
|
|
18802
|
+
}) })
|
|
18803
|
+
] });
|
|
18804
|
+
};
|
|
18805
|
+
var { Text: AntText, Title: AntTitle } = Typography;
|
|
18806
|
+
function usePinnedRecords() {
|
|
18807
|
+
const [groups, setGroups] = useState([]);
|
|
18808
|
+
const [loading, setLoading] = useState(true);
|
|
18809
|
+
const load = useCallback(async () => {
|
|
18810
|
+
setLoading(true);
|
|
18811
|
+
try {
|
|
18812
|
+
const res = await authenticatedFetch(`${API_URL3}/dashboard/pinned-records`);
|
|
18813
|
+
if (res.ok) {
|
|
18814
|
+
const data = await res.json();
|
|
18815
|
+
setGroups(data.groups ?? []);
|
|
18816
|
+
}
|
|
18817
|
+
} catch {
|
|
18818
|
+
} finally {
|
|
18819
|
+
setLoading(false);
|
|
18820
|
+
}
|
|
18821
|
+
}, []);
|
|
18822
|
+
React6.useEffect(() => {
|
|
18823
|
+
load();
|
|
18824
|
+
}, [load]);
|
|
18825
|
+
return { groups, loading, reload: load };
|
|
18826
|
+
}
|
|
18827
|
+
var PinnedRecordsPanel = () => {
|
|
18828
|
+
const { token } = theme.useToken();
|
|
18829
|
+
const allModels = useAllModels();
|
|
18830
|
+
const { groups, loading, reload } = usePinnedRecords();
|
|
18831
|
+
const [unpinning, setUnpinning] = useState(/* @__PURE__ */ new Set());
|
|
18832
|
+
const visibleGroups = groups.filter((g) => findModelByName(allModels, g.resource));
|
|
18833
|
+
const handleUnpin = useCallback(async (resource, recordId) => {
|
|
18834
|
+
const key = `${resource}:${recordId}`;
|
|
18835
|
+
setUnpinning((prev) => new Set(prev).add(key));
|
|
18836
|
+
try {
|
|
18837
|
+
await unpinRecords(resource, [recordId]);
|
|
18838
|
+
await reload();
|
|
18839
|
+
} finally {
|
|
18840
|
+
setUnpinning((prev) => {
|
|
18841
|
+
const next = new Set(prev);
|
|
18842
|
+
next.delete(key);
|
|
18843
|
+
return next;
|
|
18844
|
+
});
|
|
18845
|
+
}
|
|
18846
|
+
}, [reload]);
|
|
18847
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "16px 0" }, children: [
|
|
18848
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 20, paddingLeft: 4 }, children: [
|
|
18849
|
+
/* @__PURE__ */ jsx(PushpinFilled, { style: { color: "#faad14", fontSize: 14 } }),
|
|
18850
|
+
/* @__PURE__ */ jsx(AntText, { type: "secondary", children: "Records you've pinned across the app" }),
|
|
18851
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Refresh", children: /* @__PURE__ */ jsx(
|
|
18852
|
+
ReloadOutlined,
|
|
18853
|
+
{
|
|
18854
|
+
style: { color: token.colorTextTertiary, cursor: "pointer", fontSize: 13 },
|
|
18855
|
+
onClick: reload
|
|
18856
|
+
}
|
|
18857
|
+
) }),
|
|
18858
|
+
!loading && /* @__PURE__ */ jsxs(AntText, { type: "secondary", style: { fontSize: 12 }, children: [
|
|
18859
|
+
visibleGroups.reduce((n, g) => n + g.records.length, 0),
|
|
18860
|
+
" pins across ",
|
|
18861
|
+
visibleGroups.length,
|
|
18862
|
+
" models"
|
|
18863
|
+
] })
|
|
18864
|
+
] }),
|
|
18865
|
+
loading ? /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", padding: 48 }, children: /* @__PURE__ */ jsx(Spin, {}) }) : visibleGroups.length === 0 ? /* @__PURE__ */ jsx(
|
|
18866
|
+
Empty,
|
|
18867
|
+
{
|
|
18868
|
+
description: /* @__PURE__ */ jsxs("span", { children: [
|
|
18869
|
+
"No pinned records yet.",
|
|
18870
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
18871
|
+
/* @__PURE__ */ jsxs(AntText, { type: "secondary", style: { fontSize: 12 }, children: [
|
|
18872
|
+
"Open any record and click the ",
|
|
18873
|
+
/* @__PURE__ */ jsx(PushpinOutlined, {}),
|
|
18874
|
+
" pin button to pin it here."
|
|
18875
|
+
] })
|
|
18876
|
+
] }),
|
|
18877
|
+
image: Empty.PRESENTED_IMAGE_SIMPLE,
|
|
18878
|
+
style: { padding: 48 }
|
|
18879
|
+
}
|
|
18880
|
+
) : /* @__PURE__ */ jsx(Space, { direction: "vertical", size: 24, style: { width: "100%" }, children: visibleGroups.map((group) => {
|
|
18881
|
+
const model = findModelByName(allModels, group.resource);
|
|
18882
|
+
const tone = getModelTone(model?.name ?? group.resource);
|
|
18883
|
+
const label = model?.label ?? group.model_name;
|
|
18884
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
18885
|
+
/* @__PURE__ */ jsxs("div", { style: {
|
|
18886
|
+
display: "flex",
|
|
18887
|
+
alignItems: "center",
|
|
18888
|
+
gap: 8,
|
|
18889
|
+
marginBottom: 6,
|
|
18890
|
+
paddingBottom: 6,
|
|
18891
|
+
borderBottom: `2px solid ${tone.solid}40`
|
|
18892
|
+
}, children: [
|
|
18893
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
18894
|
+
width: 10,
|
|
18895
|
+
height: 10,
|
|
18896
|
+
borderRadius: "50%",
|
|
18897
|
+
background: tone.solid,
|
|
18898
|
+
flexShrink: 0
|
|
18899
|
+
} }),
|
|
18900
|
+
/* @__PURE__ */ jsx(AntTitle, { level: 5, style: { margin: 0, color: tone.text }, children: label }),
|
|
18901
|
+
/* @__PURE__ */ jsx(Tag, { color: tone.solid, style: { marginLeft: "auto", fontSize: 11 }, children: group.records.length })
|
|
18902
|
+
] }),
|
|
18903
|
+
/* @__PURE__ */ jsx(
|
|
18904
|
+
List$1,
|
|
18905
|
+
{
|
|
18906
|
+
size: "small",
|
|
18907
|
+
dataSource: group.records,
|
|
18908
|
+
renderItem: (rec) => {
|
|
18909
|
+
const key = `${group.resource}:${rec.id}`;
|
|
18910
|
+
return /* @__PURE__ */ jsxs(
|
|
18911
|
+
List$1.Item,
|
|
18912
|
+
{
|
|
18913
|
+
style: {
|
|
18914
|
+
padding: "4px 8px",
|
|
18915
|
+
borderRadius: token.borderRadius,
|
|
18916
|
+
transition: "background 0.15s"
|
|
18917
|
+
},
|
|
18918
|
+
className: "jm-pin-row",
|
|
18919
|
+
children: [
|
|
18920
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
18921
|
+
.jm-pin-row:hover { background: ${token.colorFillAlter}; }
|
|
18922
|
+
.jm-pin-row .jm-unpin-btn { opacity: 0; transition: opacity 0.15s; }
|
|
18923
|
+
.jm-pin-row:hover .jm-unpin-btn { opacity: 1; }
|
|
18924
|
+
` }),
|
|
18925
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, width: "100%" }, children: [
|
|
18926
|
+
/* @__PURE__ */ jsx(PushpinFilled, { style: { color: "#faad14", fontSize: 11, flexShrink: 0 } }),
|
|
18927
|
+
/* @__PURE__ */ jsx(
|
|
18928
|
+
Link,
|
|
18929
|
+
{
|
|
18930
|
+
to: `/${group.resource}/show/${rec.id}`,
|
|
18931
|
+
style: { flex: 1, color: token.colorText, fontWeight: 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
|
|
18932
|
+
children: rec._label || `#${rec.id}`
|
|
18933
|
+
}
|
|
18934
|
+
),
|
|
18935
|
+
/* @__PURE__ */ jsx(Tooltip, { title: "Unpin", children: /* @__PURE__ */ jsx(
|
|
18936
|
+
Button,
|
|
18937
|
+
{
|
|
18938
|
+
className: "jm-unpin-btn",
|
|
18939
|
+
type: "text",
|
|
18940
|
+
size: "small",
|
|
18941
|
+
icon: /* @__PURE__ */ jsx(PushpinFilled, { style: { color: "#faad14" } }),
|
|
18942
|
+
loading: unpinning.has(key),
|
|
18943
|
+
onClick: () => handleUnpin(group.resource, rec.id),
|
|
18944
|
+
style: { color: token.colorTextTertiary, height: 20, minWidth: 20, padding: "0 4px" }
|
|
18945
|
+
}
|
|
18946
|
+
) })
|
|
18947
|
+
] })
|
|
18948
|
+
]
|
|
18949
|
+
}
|
|
18950
|
+
);
|
|
18951
|
+
}
|
|
18952
|
+
}
|
|
18953
|
+
)
|
|
18954
|
+
] }, group.resource);
|
|
18955
|
+
}) })
|
|
18956
|
+
] });
|
|
18957
|
+
};
|
|
18958
|
+
var { Text: Text3 } = Typography;
|
|
18959
|
+
var _38 = window._ || ((text) => text);
|
|
18960
|
+
var DashboardPage = () => {
|
|
18961
|
+
const { token } = theme.useToken();
|
|
18962
|
+
const allModels = useAllModels();
|
|
18963
|
+
const { config, enabled, loading, save } = useDashboardConfig();
|
|
18964
|
+
if (loading) {
|
|
18965
|
+
return /* @__PURE__ */ jsx("div", { style: { display: "flex", justifyContent: "center", padding: 64 }, children: /* @__PURE__ */ jsx(Spin, {}) });
|
|
18966
|
+
}
|
|
18967
|
+
if (!enabled || !config) {
|
|
18968
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: 48 }, children: /* @__PURE__ */ jsx(
|
|
18969
|
+
Empty,
|
|
18970
|
+
{
|
|
18971
|
+
image: /* @__PURE__ */ jsx(DashboardOutlined, { style: { fontSize: 48, color: token.colorTextTertiary } }),
|
|
18972
|
+
imageStyle: { height: 60 },
|
|
18973
|
+
description: /* @__PURE__ */ jsxs("span", { children: [
|
|
18974
|
+
"No dashboard configured.",
|
|
18975
|
+
/* @__PURE__ */ jsx("br", {}),
|
|
18976
|
+
/* @__PURE__ */ jsxs(Text3, { type: "secondary", children: [
|
|
18977
|
+
"Run ",
|
|
18978
|
+
/* @__PURE__ */ jsx("code", { children: "veloiq add-dashboard <model> \u2026" }),
|
|
18979
|
+
" to get started."
|
|
18980
|
+
] })
|
|
18981
|
+
] })
|
|
18982
|
+
}
|
|
18983
|
+
) });
|
|
18984
|
+
}
|
|
18985
|
+
const tabs = [
|
|
18986
|
+
{
|
|
18987
|
+
key: "models_grid",
|
|
18988
|
+
label: _38("Models Grid"),
|
|
18989
|
+
children: /* @__PURE__ */ jsx("div", { style: { height: "calc(100vh - 140px)", overflow: "auto" }, children: /* @__PURE__ */ jsx(
|
|
18990
|
+
ViewsGrid,
|
|
18991
|
+
{
|
|
18992
|
+
config,
|
|
18993
|
+
allModels,
|
|
18994
|
+
onConfigChange: save
|
|
18995
|
+
}
|
|
18996
|
+
) })
|
|
18997
|
+
},
|
|
18998
|
+
{
|
|
18999
|
+
key: "recent_activity",
|
|
19000
|
+
label: _38("Recent Activity"),
|
|
19001
|
+
children: /* @__PURE__ */ jsx("div", { style: { height: "calc(100vh - 140px)", overflow: "auto", padding: "0 12px" }, children: /* @__PURE__ */ jsx(RecentActivityPanel, {}) })
|
|
19002
|
+
},
|
|
19003
|
+
{
|
|
19004
|
+
key: "pinned_records",
|
|
19005
|
+
label: _38("Pinned Records"),
|
|
19006
|
+
children: /* @__PURE__ */ jsx("div", { style: { height: "calc(100vh - 140px)", overflow: "auto", padding: "0 12px" }, children: /* @__PURE__ */ jsx(PinnedRecordsPanel, {}) })
|
|
19007
|
+
}
|
|
19008
|
+
];
|
|
19009
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "0 16px", height: "100%" }, children: /* @__PURE__ */ jsx(
|
|
19010
|
+
Tabs,
|
|
19011
|
+
{
|
|
19012
|
+
items: tabs,
|
|
19013
|
+
tabBarStyle: { marginBottom: 0 }
|
|
19014
|
+
}
|
|
19015
|
+
) });
|
|
19016
|
+
};
|
|
18165
19017
|
|
|
18166
19018
|
// src/utils/generateResources.ts
|
|
18167
19019
|
function generateResources(models, moduleName, options = {}) {
|
|
@@ -18305,6 +19157,6 @@ var authSystemModels = [
|
|
|
18305
19157
|
}
|
|
18306
19158
|
];
|
|
18307
19159
|
|
|
18308
|
-
export { API_URL3 as API_URL, AllModelsProvider, ColorModeContext, ColorModeContextProvider, CustomSider, DynamicCreate, DynamicEdit, DynamicList, DynamicShow, ExecutableHtml, GlobalSearch, HierarchyView, HorizontalMenu, InlinePlotlyHtml, LayoutWrapper, LoginPage, ModelHeading, MultiPaneLayout, PaneNavigationContext, PrimaryShowContext, ReferenceField, ResourceContext, ShowFooterButtons, StandardList, StandardShow, accessControlProvider, authProvider, authSystemModels, authenticatedFetch, buildShowTabFormOptions, generateResources, getModelTone, httpClient, normalizeToneKey, renderRelationBlock, setColorSchemas, useAllModels, useKeyboardShortcuts, useMetadataModal, usePaneNavigation, useShowActionsPreferences, useShowEditableForm, useStandardShowTabs };
|
|
19160
|
+
export { API_URL3 as API_URL, AllModelsProvider, ColorModeContext, ColorModeContextProvider, CustomSider, DashboardPage, DynamicCreate, DynamicEdit, DynamicList, DynamicShow, ExecutableHtml, GlobalSearch, HierarchyView, HorizontalMenu, InlinePlotlyHtml, LayoutWrapper, LoginPage, ModelHeading, MultiPaneLayout, PaneNavigationContext, PinnedRecordsPanel, PrimaryShowContext, RecentActivityPanel, ReferenceField, ResourceContext, ShowFooterButtons, StandardList, StandardShow, ViewsGrid, accessControlProvider, authProvider, authSystemModels, authenticatedFetch, buildShowTabFormOptions, generateResources, getModelTone, httpClient, normalizeToneKey, renderRelationBlock, setColorSchemas, useAllModels, useKeyboardShortcuts, useMetadataModal, usePaneNavigation, useShowActionsPreferences, useShowEditableForm, useStandardShowTabs };
|
|
18309
19161
|
//# sourceMappingURL=index.mjs.map
|
|
18310
19162
|
//# sourceMappingURL=index.mjs.map
|