@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/dist/index.d.cts CHANGED
@@ -196,7 +196,20 @@ type ExportColumnRef = {
196
196
  key: string;
197
197
  header: string;
198
198
  };
199
- declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAdd, addLabel, canAdd, onView, onUpdate, onDelete, canUpdate, canDelete, onDownload, canDownload, downloadBusy, showColumnPicker, columnPrefsKey, visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange, toolbar, form, }: {
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
- /** Persist visible column keys in localStorage under this key. */
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
- declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAdd, addLabel, canAdd, onView, onUpdate, onDelete, canUpdate, canDelete, onDownload, canDownload, downloadBusy, showColumnPicker, columnPrefsKey, visibleColumnKeys, defaultVisibleColumnKeys, onVisibleColumnKeysChange, toolbar, form, }: {
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
- /** Persist visible column keys in localStorage under this key. */
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 [filters, setFilters] = useState({});
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(false);
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(false);
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 showDownload = Boolean(onDownload) && canDownload;
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) => ({ ...current, [key]: value }));
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
- setSideOpen(true);
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
- setSideOpen(true);
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: () => setSideOpen((open) => !open),
1820
+ onClick: () => setSideOpenValue(!sideOpen),
1603
1821
  children: [
1604
1822
  /* @__PURE__ */ jsx(ChevronIcon, { open: sideOpen }),
1605
1823
  sideOpen ? /* @__PURE__ */ jsx("span", { children: "Collapse" }) : null