@mshuja288/aksuicore 0.4.1 → 0.4.3
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/CHANGELOG.md +7 -0
- package/dist/aksui.css +75 -1
- package/dist/index.cjs +226 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -3
- package/dist/index.d.ts +25 -3
- package/dist/index.js +226 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
- package/src/patterns/RecordWorkspace.tsx +272 -10
- package/src/patterns/index.ts +3 -0
- package/src/theme/patterns.css +75 -1
package/dist/index.d.cts
CHANGED
|
@@ -196,7 +196,20 @@ type ExportColumnRef = {
|
|
|
196
196
|
key: string;
|
|
197
197
|
header: string;
|
|
198
198
|
};
|
|
199
|
-
|
|
199
|
+
type BulkImportMode = "insert" | "update" | "upsert";
|
|
200
|
+
type BulkImportError = {
|
|
201
|
+
row: number;
|
|
202
|
+
field?: string | null;
|
|
203
|
+
code: string;
|
|
204
|
+
message: string;
|
|
205
|
+
};
|
|
206
|
+
type BulkImportResult = {
|
|
207
|
+
totalRows: number;
|
|
208
|
+
failed: number;
|
|
209
|
+
applied: boolean;
|
|
210
|
+
errors: BulkImportError[];
|
|
211
|
+
};
|
|
212
|
+
declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAdd, addLabel, canAdd, onView, onUpdate, onDelete, canUpdate, canDelete, onDownload, canDownload, canExport, downloadBusy, onBulkImport, canImport, importBusy, showColumnPicker, columnPrefsKey, visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange, toolbar, form, }: {
|
|
200
213
|
title: string;
|
|
201
214
|
columns: TableColumn<T>[];
|
|
202
215
|
items: T[];
|
|
@@ -215,11 +228,20 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
|
|
|
215
228
|
* Second argument lists currently visible columns (exportKey ?? key).
|
|
216
229
|
*/
|
|
217
230
|
onDownload?: (format: ExportDownloadFormat, columns: ExportColumnRef[]) => void;
|
|
231
|
+
/** Alias for `canDownload` (RBAC). When set, export requires this and `canDownload` to be true. */
|
|
232
|
+
canExport?: boolean;
|
|
218
233
|
canDownload?: boolean;
|
|
219
234
|
downloadBusy?: boolean;
|
|
235
|
+
onBulkImport?: (mode: BulkImportMode, file: File) => Promise<BulkImportResult>;
|
|
236
|
+
canImport?: boolean;
|
|
237
|
+
importBusy?: boolean;
|
|
220
238
|
/** Column checklist in the side rail. Default true. */
|
|
221
239
|
showColumnPicker?: boolean;
|
|
222
|
-
/**
|
|
240
|
+
/**
|
|
241
|
+
* Persist visible column keys in localStorage under this key.
|
|
242
|
+
* Also persists filter values at `${columnPrefsKey}.filters`.
|
|
243
|
+
* Preview + side-rail open/collapsed use a shared key across all tables (`aksui.workspace.chrome`).
|
|
244
|
+
*/
|
|
223
245
|
columnPrefsKey?: string;
|
|
224
246
|
/** Controlled visible column keys. */
|
|
225
247
|
visibleColumnKeys?: string[];
|
|
@@ -233,4 +255,4 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
|
|
|
233
255
|
/** @deprecated Prefer RecordWorkspace — alias kept for configurator migration */
|
|
234
256
|
declare const RecordTable: typeof RecordWorkspace;
|
|
235
257
|
|
|
236
|
-
export { type AksuiTokenName, AppSelect, type AppSelectOption, AppShell, type AppShellProps, Button, type ButtonVariant, ConfirmDeleteDialog, DateField, Dialog, type ExportColumnRef, type ExportDownloadFormat, FormActions, FormDialog, type MobileNavMode, type PageSizeOption, Pagination, RecordTable, RecordWorkspace, Select, type SelectOption, SideNav, type SideNavItem, Snackbar, StatusMessage, type TableColumn, Topbar, aksuiThemeVersion, aksuiTokens };
|
|
258
|
+
export { type AksuiTokenName, AppSelect, type AppSelectOption, AppShell, type AppShellProps, type BulkImportError, type BulkImportMode, type BulkImportResult, Button, type ButtonVariant, ConfirmDeleteDialog, DateField, Dialog, type ExportColumnRef, type ExportDownloadFormat, FormActions, FormDialog, type MobileNavMode, type PageSizeOption, Pagination, RecordTable, RecordWorkspace, Select, type SelectOption, SideNav, type SideNavItem, Snackbar, StatusMessage, type TableColumn, Topbar, aksuiThemeVersion, aksuiTokens };
|
package/dist/index.d.ts
CHANGED
|
@@ -196,7 +196,20 @@ type ExportColumnRef = {
|
|
|
196
196
|
key: string;
|
|
197
197
|
header: string;
|
|
198
198
|
};
|
|
199
|
-
|
|
199
|
+
type BulkImportMode = "insert" | "update" | "upsert";
|
|
200
|
+
type BulkImportError = {
|
|
201
|
+
row: number;
|
|
202
|
+
field?: string | null;
|
|
203
|
+
code: string;
|
|
204
|
+
message: string;
|
|
205
|
+
};
|
|
206
|
+
type BulkImportResult = {
|
|
207
|
+
totalRows: number;
|
|
208
|
+
failed: number;
|
|
209
|
+
applied: boolean;
|
|
210
|
+
errors: BulkImportError[];
|
|
211
|
+
};
|
|
212
|
+
declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAdd, addLabel, canAdd, onView, onUpdate, onDelete, canUpdate, canDelete, onDownload, canDownload, canExport, downloadBusy, onBulkImport, canImport, importBusy, showColumnPicker, columnPrefsKey, visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange, toolbar, form, }: {
|
|
200
213
|
title: string;
|
|
201
214
|
columns: TableColumn<T>[];
|
|
202
215
|
items: T[];
|
|
@@ -215,11 +228,20 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
|
|
|
215
228
|
* Second argument lists currently visible columns (exportKey ?? key).
|
|
216
229
|
*/
|
|
217
230
|
onDownload?: (format: ExportDownloadFormat, columns: ExportColumnRef[]) => void;
|
|
231
|
+
/** Alias for `canDownload` (RBAC). When set, export requires this and `canDownload` to be true. */
|
|
232
|
+
canExport?: boolean;
|
|
218
233
|
canDownload?: boolean;
|
|
219
234
|
downloadBusy?: boolean;
|
|
235
|
+
onBulkImport?: (mode: BulkImportMode, file: File) => Promise<BulkImportResult>;
|
|
236
|
+
canImport?: boolean;
|
|
237
|
+
importBusy?: boolean;
|
|
220
238
|
/** Column checklist in the side rail. Default true. */
|
|
221
239
|
showColumnPicker?: boolean;
|
|
222
|
-
/**
|
|
240
|
+
/**
|
|
241
|
+
* Persist visible column keys in localStorage under this key.
|
|
242
|
+
* Also persists filter values at `${columnPrefsKey}.filters`.
|
|
243
|
+
* Preview + side-rail open/collapsed use a shared key across all tables (`aksui.workspace.chrome`).
|
|
244
|
+
*/
|
|
223
245
|
columnPrefsKey?: string;
|
|
224
246
|
/** Controlled visible column keys. */
|
|
225
247
|
visibleColumnKeys?: string[];
|
|
@@ -233,4 +255,4 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
|
|
|
233
255
|
/** @deprecated Prefer RecordWorkspace — alias kept for configurator migration */
|
|
234
256
|
declare const RecordTable: typeof RecordWorkspace;
|
|
235
257
|
|
|
236
|
-
export { type AksuiTokenName, AppSelect, type AppSelectOption, AppShell, type AppShellProps, Button, type ButtonVariant, ConfirmDeleteDialog, DateField, Dialog, type ExportColumnRef, type ExportDownloadFormat, FormActions, FormDialog, type MobileNavMode, type PageSizeOption, Pagination, RecordTable, RecordWorkspace, Select, type SelectOption, SideNav, type SideNavItem, Snackbar, StatusMessage, type TableColumn, Topbar, aksuiThemeVersion, aksuiTokens };
|
|
258
|
+
export { type AksuiTokenName, AppSelect, type AppSelectOption, AppShell, type AppShellProps, type BulkImportError, type BulkImportMode, type BulkImportResult, Button, type ButtonVariant, ConfirmDeleteDialog, DateField, Dialog, type ExportColumnRef, type ExportDownloadFormat, FormActions, FormDialog, type MobileNavMode, type PageSizeOption, Pagination, RecordTable, RecordWorkspace, Select, type SelectOption, SideNav, type SideNavItem, Snackbar, StatusMessage, type TableColumn, Topbar, aksuiThemeVersion, aksuiTokens };
|
package/dist/index.js
CHANGED
|
@@ -867,9 +867,45 @@ var EXPORT_FORMAT_OPTIONS = [
|
|
|
867
867
|
{ format: "xlsx", label: "Excel" },
|
|
868
868
|
{ format: "json", label: "JSON" }
|
|
869
869
|
];
|
|
870
|
+
var BULK_IMPORT_MODE_OPTIONS = [
|
|
871
|
+
{ mode: "insert", label: "Insert" },
|
|
872
|
+
{ mode: "update", label: "Update" },
|
|
873
|
+
{ mode: "upsert", label: "Upsert" }
|
|
874
|
+
];
|
|
870
875
|
function defaultVisibleKeys(columns) {
|
|
871
876
|
return columns.filter((column) => column.defaultVisible !== false).map((column) => column.key);
|
|
872
877
|
}
|
|
878
|
+
var WORKSPACE_CHROME_KEY = "aksui.workspace.chrome";
|
|
879
|
+
function readWorkspaceChrome() {
|
|
880
|
+
if (typeof window === "undefined") {
|
|
881
|
+
return { previewEnabled: false, sideOpen: false };
|
|
882
|
+
}
|
|
883
|
+
try {
|
|
884
|
+
const raw = window.localStorage.getItem(WORKSPACE_CHROME_KEY);
|
|
885
|
+
if (!raw) {
|
|
886
|
+
return { previewEnabled: false, sideOpen: false };
|
|
887
|
+
}
|
|
888
|
+
const parsed = JSON.parse(raw);
|
|
889
|
+
return {
|
|
890
|
+
previewEnabled: Boolean(parsed.previewEnabled),
|
|
891
|
+
sideOpen: Boolean(parsed.sideOpen)
|
|
892
|
+
};
|
|
893
|
+
} catch {
|
|
894
|
+
return { previewEnabled: false, sideOpen: false };
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function writeWorkspaceChrome(chrome) {
|
|
898
|
+
if (typeof window === "undefined") {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
try {
|
|
902
|
+
window.localStorage.setItem(WORKSPACE_CHROME_KEY, JSON.stringify(chrome));
|
|
903
|
+
} catch {
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
function filtersPrefsKey(columnPrefsKey) {
|
|
907
|
+
return columnPrefsKey ? `${columnPrefsKey}.filters` : void 0;
|
|
908
|
+
}
|
|
873
909
|
function readStoredColumnKeys(prefsKey, fallback, allowed) {
|
|
874
910
|
if (!prefsKey || typeof window === "undefined") {
|
|
875
911
|
return fallback;
|
|
@@ -898,6 +934,45 @@ function writeStoredColumnKeys(prefsKey, keys) {
|
|
|
898
934
|
} catch {
|
|
899
935
|
}
|
|
900
936
|
}
|
|
937
|
+
function readStoredFilters(prefsKey, allowed) {
|
|
938
|
+
if (!prefsKey || typeof window === "undefined") {
|
|
939
|
+
return {};
|
|
940
|
+
}
|
|
941
|
+
try {
|
|
942
|
+
const raw = window.localStorage.getItem(prefsKey);
|
|
943
|
+
if (!raw) {
|
|
944
|
+
return {};
|
|
945
|
+
}
|
|
946
|
+
const parsed = JSON.parse(raw);
|
|
947
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
948
|
+
return {};
|
|
949
|
+
}
|
|
950
|
+
const next = {};
|
|
951
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
952
|
+
if (allowed.has(key) && typeof value === "string" && value.trim()) {
|
|
953
|
+
next[key] = value;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
return next;
|
|
957
|
+
} catch {
|
|
958
|
+
return {};
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
function writeStoredFilters(prefsKey, filters) {
|
|
962
|
+
if (!prefsKey || typeof window === "undefined") {
|
|
963
|
+
return;
|
|
964
|
+
}
|
|
965
|
+
try {
|
|
966
|
+
const trimmed = {};
|
|
967
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
968
|
+
if (value.trim()) {
|
|
969
|
+
trimmed[key] = value;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
window.localStorage.setItem(prefsKey, JSON.stringify(trimmed));
|
|
973
|
+
} catch {
|
|
974
|
+
}
|
|
975
|
+
}
|
|
901
976
|
function compareColumnValues(column, left, right) {
|
|
902
977
|
const leftRaw = column.display ? column.display(left) : column.value(left);
|
|
903
978
|
const rightRaw = column.display ? column.display(right) : column.value(right);
|
|
@@ -943,6 +1018,13 @@ function PreviewIcon() {
|
|
|
943
1018
|
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
|
|
944
1019
|
] });
|
|
945
1020
|
}
|
|
1021
|
+
function UploadIcon() {
|
|
1022
|
+
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
|
|
1023
|
+
/* @__PURE__ */ jsx("path", { d: "M10 16.5V7.3", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
|
|
1024
|
+
/* @__PURE__ */ jsx("path", { d: "M6.5 10.8 10 7.2l3.5 3.6", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
1025
|
+
/* @__PURE__ */ jsx("path", { d: "M4 4.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
|
|
1026
|
+
] });
|
|
1027
|
+
}
|
|
946
1028
|
function DownloadIcon() {
|
|
947
1029
|
return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
|
|
948
1030
|
/* @__PURE__ */ jsx("path", { d: "M10 3.5v8.2", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
|
|
@@ -992,7 +1074,11 @@ function RecordWorkspace({
|
|
|
992
1074
|
canDelete,
|
|
993
1075
|
onDownload,
|
|
994
1076
|
canDownload = true,
|
|
1077
|
+
canExport,
|
|
995
1078
|
downloadBusy = false,
|
|
1079
|
+
onBulkImport,
|
|
1080
|
+
canImport = true,
|
|
1081
|
+
importBusy = false,
|
|
996
1082
|
showColumnPicker = true,
|
|
997
1083
|
columnPrefsKey,
|
|
998
1084
|
visibleColumnKeys,
|
|
@@ -1010,13 +1096,21 @@ function RecordWorkspace({
|
|
|
1010
1096
|
const [internalVisibleKeys, setInternalVisibleKeys] = useState(
|
|
1011
1097
|
() => readStoredColumnKeys(columnPrefsKey, fallbackKeys, allowedKeys)
|
|
1012
1098
|
);
|
|
1013
|
-
const
|
|
1099
|
+
const filterStorageKey = filtersPrefsKey(columnPrefsKey);
|
|
1100
|
+
const [filters, setFilters] = useState(
|
|
1101
|
+
() => readStoredFilters(filterStorageKey, allowedKeys)
|
|
1102
|
+
);
|
|
1014
1103
|
const [sort, setSort] = useState(null);
|
|
1015
|
-
const [sideOpen, setSideOpen] = useState(
|
|
1104
|
+
const [sideOpen, setSideOpen] = useState(() => readWorkspaceChrome().sideOpen);
|
|
1016
1105
|
const [toolsDrawerOpen, setToolsDrawerOpen] = useState(false);
|
|
1017
1106
|
const [downloadOpen, setDownloadOpen] = useState(false);
|
|
1107
|
+
const [bulkOpen, setBulkOpen] = useState(false);
|
|
1108
|
+
const [bulkMode, setBulkMode] = useState("upsert");
|
|
1109
|
+
const [bulkFile, setBulkFile] = useState(null);
|
|
1110
|
+
const [bulkReport, setBulkReport] = useState(null);
|
|
1111
|
+
const bulkFileInputRef = useRef(null);
|
|
1018
1112
|
const [columnsOpen, setColumnsOpen] = useState(false);
|
|
1019
|
-
const [previewEnabled, setPreviewEnabled] = useState(
|
|
1113
|
+
const [previewEnabled, setPreviewEnabled] = useState(() => readWorkspaceChrome().previewEnabled);
|
|
1020
1114
|
const [previewKey, setPreviewKey] = useState(null);
|
|
1021
1115
|
const [tooltip, setTooltip] = useState(null);
|
|
1022
1116
|
const [pageSize, setPageSize] = useState("15");
|
|
@@ -1031,6 +1125,9 @@ function RecordWorkspace({
|
|
|
1031
1125
|
}
|
|
1032
1126
|
setInternalVisibleKeys(readStoredColumnKeys(columnPrefsKey, fallbackKeys, allowedKeys));
|
|
1033
1127
|
}, [allowedKeys, columnPrefsKey, fallbackKeys, isControlled]);
|
|
1128
|
+
useEffect(() => {
|
|
1129
|
+
setFilters(readStoredFilters(filtersPrefsKey(columnPrefsKey), allowedKeys));
|
|
1130
|
+
}, [allowedKeys, columnPrefsKey]);
|
|
1034
1131
|
const resolvedVisibleKeys = useMemo(() => {
|
|
1035
1132
|
const source = isControlled ? visibleColumnKeys : internalVisibleKeys;
|
|
1036
1133
|
const filtered2 = source.filter((key) => allowedKeys.has(key));
|
|
@@ -1109,7 +1206,9 @@ function RecordWorkspace({
|
|
|
1109
1206
|
const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
|
|
1110
1207
|
const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
|
|
1111
1208
|
const showAdd = canAdd && Boolean(onAdd);
|
|
1112
|
-
const
|
|
1209
|
+
const exportAllowed = (canExport ?? true) && canDownload;
|
|
1210
|
+
const showDownload = Boolean(onDownload) && exportAllowed;
|
|
1211
|
+
const showBulkImport = Boolean(onBulkImport) && canImport;
|
|
1113
1212
|
const showFilters = filterableColumns.length > 0;
|
|
1114
1213
|
const showColumns = showColumnPicker && columns.length > 0;
|
|
1115
1214
|
const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
|
|
@@ -1154,6 +1253,29 @@ function RecordWorkspace({
|
|
|
1154
1253
|
onDownload(format, exportColumns);
|
|
1155
1254
|
setDownloadOpen(false);
|
|
1156
1255
|
}
|
|
1256
|
+
async function submitBulkImport() {
|
|
1257
|
+
if (!onBulkImport || importBusy || !bulkFile) {
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
setBulkReport(null);
|
|
1261
|
+
try {
|
|
1262
|
+
const report = await onBulkImport(bulkMode, bulkFile);
|
|
1263
|
+
setBulkReport(report);
|
|
1264
|
+
if (report.applied) {
|
|
1265
|
+
setBulkFile(null);
|
|
1266
|
+
if (bulkFileInputRef.current) {
|
|
1267
|
+
bulkFileInputRef.current.value = "";
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
} catch {
|
|
1271
|
+
setBulkReport({
|
|
1272
|
+
totalRows: 0,
|
|
1273
|
+
failed: 1,
|
|
1274
|
+
applied: false,
|
|
1275
|
+
errors: [{ row: 0, code: "ImportFailed", message: "Import request failed." }]
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1157
1279
|
function cellText(column, item) {
|
|
1158
1280
|
const raw = column.display ? column.display(item) : column.value(item);
|
|
1159
1281
|
return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
|
|
@@ -1166,13 +1288,22 @@ function RecordWorkspace({
|
|
|
1166
1288
|
}
|
|
1167
1289
|
const previewTitle = previewItem && visibleColumns[0] ? cellText(visibleColumns[0], previewItem) : null;
|
|
1168
1290
|
function changeFilter(key, value) {
|
|
1169
|
-
setFilters((current) =>
|
|
1291
|
+
setFilters((current) => {
|
|
1292
|
+
const next = { ...current, [key]: value };
|
|
1293
|
+
writeStoredFilters(filterStorageKey, next);
|
|
1294
|
+
return next;
|
|
1295
|
+
});
|
|
1170
1296
|
setPage(1);
|
|
1171
1297
|
}
|
|
1172
1298
|
function clearFilters() {
|
|
1173
1299
|
setFilters({});
|
|
1300
|
+
writeStoredFilters(filterStorageKey, {});
|
|
1174
1301
|
setPage(1);
|
|
1175
1302
|
}
|
|
1303
|
+
function setSideOpenValue(open) {
|
|
1304
|
+
setSideOpen(open);
|
|
1305
|
+
writeWorkspaceChrome({ previewEnabled, sideOpen: open });
|
|
1306
|
+
}
|
|
1176
1307
|
function toggleSort(column) {
|
|
1177
1308
|
if (column.sortable === false) {
|
|
1178
1309
|
return;
|
|
@@ -1190,6 +1321,7 @@ function RecordWorkspace({
|
|
|
1190
1321
|
}
|
|
1191
1322
|
function setPreviewEnabledValue(enabled) {
|
|
1192
1323
|
setPreviewEnabled(enabled);
|
|
1324
|
+
writeWorkspaceChrome({ previewEnabled: enabled, sideOpen });
|
|
1193
1325
|
setTooltip(null);
|
|
1194
1326
|
if (!enabled) {
|
|
1195
1327
|
setPreviewKey(null);
|
|
@@ -1250,7 +1382,7 @@ function RecordWorkspace({
|
|
|
1250
1382
|
title: "Columns",
|
|
1251
1383
|
"aria-label": "Columns",
|
|
1252
1384
|
onClick: () => {
|
|
1253
|
-
|
|
1385
|
+
setSideOpenValue(true);
|
|
1254
1386
|
setColumnsOpen(true);
|
|
1255
1387
|
},
|
|
1256
1388
|
children: [
|
|
@@ -1268,12 +1400,27 @@ function RecordWorkspace({
|
|
|
1268
1400
|
"aria-label": "Download",
|
|
1269
1401
|
disabled: downloadBusy,
|
|
1270
1402
|
onClick: () => {
|
|
1271
|
-
|
|
1403
|
+
setSideOpenValue(true);
|
|
1272
1404
|
setDownloadOpen(true);
|
|
1273
1405
|
},
|
|
1274
1406
|
children: /* @__PURE__ */ jsx(DownloadIcon, {})
|
|
1275
1407
|
}
|
|
1276
1408
|
) : null,
|
|
1409
|
+
showBulkImport ? /* @__PURE__ */ jsx(
|
|
1410
|
+
"button",
|
|
1411
|
+
{
|
|
1412
|
+
type: "button",
|
|
1413
|
+
className: "ghost side-rail-icon",
|
|
1414
|
+
title: "Bulk entry",
|
|
1415
|
+
"aria-label": "Bulk entry",
|
|
1416
|
+
disabled: importBusy,
|
|
1417
|
+
onClick: () => {
|
|
1418
|
+
setSideOpenValue(true);
|
|
1419
|
+
setBulkOpen(true);
|
|
1420
|
+
},
|
|
1421
|
+
children: /* @__PURE__ */ jsx(UploadIcon, {})
|
|
1422
|
+
}
|
|
1423
|
+
) : null,
|
|
1277
1424
|
showFilters ? /* @__PURE__ */ jsxs(
|
|
1278
1425
|
"button",
|
|
1279
1426
|
{
|
|
@@ -1398,6 +1545,77 @@ function RecordWorkspace({
|
|
|
1398
1545
|
option.format
|
|
1399
1546
|
)) }) : null
|
|
1400
1547
|
] }) : null,
|
|
1548
|
+
showBulkImport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk", children: [
|
|
1549
|
+
/* @__PURE__ */ jsxs(
|
|
1550
|
+
"button",
|
|
1551
|
+
{
|
|
1552
|
+
type: "button",
|
|
1553
|
+
className: "ghost side-rail-bulk-toggle",
|
|
1554
|
+
"aria-expanded": bulkOpen,
|
|
1555
|
+
disabled: importBusy,
|
|
1556
|
+
onClick: () => setBulkOpen((open) => !open),
|
|
1557
|
+
children: [
|
|
1558
|
+
/* @__PURE__ */ jsx(UploadIcon, {}),
|
|
1559
|
+
/* @__PURE__ */ jsx("span", { children: importBusy ? "Importing\u2026" : "Bulk entry" })
|
|
1560
|
+
]
|
|
1561
|
+
}
|
|
1562
|
+
),
|
|
1563
|
+
bulkOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-panel", role: "group", "aria-label": "Bulk entry", children: [
|
|
1564
|
+
/* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-mode", children: [
|
|
1565
|
+
"Mode",
|
|
1566
|
+
/* @__PURE__ */ jsx(
|
|
1567
|
+
Select,
|
|
1568
|
+
{
|
|
1569
|
+
value: bulkMode,
|
|
1570
|
+
options: BULK_IMPORT_MODE_OPTIONS.map((option) => ({ value: option.mode, label: option.label })),
|
|
1571
|
+
onChange: (value) => setBulkMode(value)
|
|
1572
|
+
}
|
|
1573
|
+
)
|
|
1574
|
+
] }),
|
|
1575
|
+
/* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-file", children: [
|
|
1576
|
+
"File",
|
|
1577
|
+
/* @__PURE__ */ jsx(
|
|
1578
|
+
"input",
|
|
1579
|
+
{
|
|
1580
|
+
ref: bulkFileInputRef,
|
|
1581
|
+
type: "file",
|
|
1582
|
+
accept: ".csv,.xlsx,.json",
|
|
1583
|
+
disabled: importBusy,
|
|
1584
|
+
onChange: (event) => {
|
|
1585
|
+
setBulkFile(event.target.files?.[0] ?? null);
|
|
1586
|
+
setBulkReport(null);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
)
|
|
1590
|
+
] }),
|
|
1591
|
+
/* @__PURE__ */ jsx(
|
|
1592
|
+
"button",
|
|
1593
|
+
{
|
|
1594
|
+
type: "button",
|
|
1595
|
+
className: "side-rail-bulk-submit",
|
|
1596
|
+
disabled: importBusy || !bulkFile,
|
|
1597
|
+
onClick: () => void submitBulkImport(),
|
|
1598
|
+
children: importBusy ? "Importing\u2026" : "Import"
|
|
1599
|
+
}
|
|
1600
|
+
),
|
|
1601
|
+
bulkReport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-report", role: "status", children: [
|
|
1602
|
+
/* @__PURE__ */ jsx("p", { children: bulkReport.applied ? `Applied ${bulkReport.totalRows} row(s).` : `${bulkReport.failed} error(s) in ${bulkReport.totalRows} row(s).` }),
|
|
1603
|
+
bulkReport.errors.length > 0 ? /* @__PURE__ */ jsxs("ul", { className: "side-rail-bulk-errors", children: [
|
|
1604
|
+
bulkReport.errors.slice(0, 8).map((error, index) => /* @__PURE__ */ jsxs("li", { children: [
|
|
1605
|
+
"Row ",
|
|
1606
|
+
error.row,
|
|
1607
|
+
": ",
|
|
1608
|
+
error.message
|
|
1609
|
+
] }, `${error.row}-${error.code}-${index}`)),
|
|
1610
|
+
bulkReport.errors.length > 8 ? /* @__PURE__ */ jsxs("li", { children: [
|
|
1611
|
+
"\u2026and ",
|
|
1612
|
+
bulkReport.errors.length - 8,
|
|
1613
|
+
" more"
|
|
1614
|
+
] }) : null
|
|
1615
|
+
] }) : null
|
|
1616
|
+
] }) : null
|
|
1617
|
+
] }) : null
|
|
1618
|
+
] }) : null,
|
|
1401
1619
|
showFilters ? /* @__PURE__ */ jsxs("div", { className: "side-rail-filters", children: [
|
|
1402
1620
|
/* @__PURE__ */ jsxs("div", { className: "filter-panel-head", children: [
|
|
1403
1621
|
/* @__PURE__ */ jsx("h3", { children: "Filters" }),
|
|
@@ -1599,7 +1817,7 @@ function RecordWorkspace({
|
|
|
1599
1817
|
className: "ghost side-rail-toggle",
|
|
1600
1818
|
"aria-expanded": sideOpen,
|
|
1601
1819
|
title: sideOpen ? "Collapse" : "Expand",
|
|
1602
|
-
onClick: () =>
|
|
1820
|
+
onClick: () => setSideOpenValue(!sideOpen),
|
|
1603
1821
|
children: [
|
|
1604
1822
|
/* @__PURE__ */ jsx(ChevronIcon, { open: sideOpen }),
|
|
1605
1823
|
sideOpen ? /* @__PURE__ */ jsx("span", { children: "Collapse" }) : null
|