@mshuja288/aksuicore 0.4.1 → 0.4.2

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,8 +228,13 @@ 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
  /** Persist visible column keys in localStorage under this key. */
@@ -233,4 +251,4 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
233
251
  /** @deprecated Prefer RecordWorkspace — alias kept for configurator migration */
234
252
  declare const RecordTable: typeof RecordWorkspace;
235
253
 
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 };
254
+ 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,8 +228,13 @@ 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
  /** Persist visible column keys in localStorage under this key. */
@@ -233,4 +251,4 @@ declare function RecordWorkspace<T>({ title, columns, items, rowKey, empty, onAd
233
251
  /** @deprecated Prefer RecordWorkspace — alias kept for configurator migration */
234
252
  declare const RecordTable: typeof RecordWorkspace;
235
253
 
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 };
254
+ 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,6 +867,11 @@ 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
  }
@@ -943,6 +948,13 @@ function PreviewIcon() {
943
948
  /* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
944
949
  ] });
945
950
  }
951
+ function UploadIcon() {
952
+ return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
953
+ /* @__PURE__ */ jsx("path", { d: "M10 16.5V7.3", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
954
+ /* @__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" }),
955
+ /* @__PURE__ */ jsx("path", { d: "M4 4.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
956
+ ] });
957
+ }
946
958
  function DownloadIcon() {
947
959
  return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
948
960
  /* @__PURE__ */ jsx("path", { d: "M10 3.5v8.2", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
@@ -992,7 +1004,11 @@ function RecordWorkspace({
992
1004
  canDelete,
993
1005
  onDownload,
994
1006
  canDownload = true,
1007
+ canExport,
995
1008
  downloadBusy = false,
1009
+ onBulkImport,
1010
+ canImport = true,
1011
+ importBusy = false,
996
1012
  showColumnPicker = true,
997
1013
  columnPrefsKey,
998
1014
  visibleColumnKeys,
@@ -1015,6 +1031,11 @@ function RecordWorkspace({
1015
1031
  const [sideOpen, setSideOpen] = useState(false);
1016
1032
  const [toolsDrawerOpen, setToolsDrawerOpen] = useState(false);
1017
1033
  const [downloadOpen, setDownloadOpen] = useState(false);
1034
+ const [bulkOpen, setBulkOpen] = useState(false);
1035
+ const [bulkMode, setBulkMode] = useState("upsert");
1036
+ const [bulkFile, setBulkFile] = useState(null);
1037
+ const [bulkReport, setBulkReport] = useState(null);
1038
+ const bulkFileInputRef = useRef(null);
1018
1039
  const [columnsOpen, setColumnsOpen] = useState(false);
1019
1040
  const [previewEnabled, setPreviewEnabled] = useState(false);
1020
1041
  const [previewKey, setPreviewKey] = useState(null);
@@ -1109,7 +1130,9 @@ function RecordWorkspace({
1109
1130
  const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
1110
1131
  const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
1111
1132
  const showAdd = canAdd && Boolean(onAdd);
1112
- const showDownload = Boolean(onDownload) && canDownload;
1133
+ const exportAllowed = (canExport ?? true) && canDownload;
1134
+ const showDownload = Boolean(onDownload) && exportAllowed;
1135
+ const showBulkImport = Boolean(onBulkImport) && canImport;
1113
1136
  const showFilters = filterableColumns.length > 0;
1114
1137
  const showColumns = showColumnPicker && columns.length > 0;
1115
1138
  const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
@@ -1154,6 +1177,29 @@ function RecordWorkspace({
1154
1177
  onDownload(format, exportColumns);
1155
1178
  setDownloadOpen(false);
1156
1179
  }
1180
+ async function submitBulkImport() {
1181
+ if (!onBulkImport || importBusy || !bulkFile) {
1182
+ return;
1183
+ }
1184
+ setBulkReport(null);
1185
+ try {
1186
+ const report = await onBulkImport(bulkMode, bulkFile);
1187
+ setBulkReport(report);
1188
+ if (report.applied) {
1189
+ setBulkFile(null);
1190
+ if (bulkFileInputRef.current) {
1191
+ bulkFileInputRef.current.value = "";
1192
+ }
1193
+ }
1194
+ } catch {
1195
+ setBulkReport({
1196
+ totalRows: 0,
1197
+ failed: 1,
1198
+ applied: false,
1199
+ errors: [{ row: 0, code: "ImportFailed", message: "Import request failed." }]
1200
+ });
1201
+ }
1202
+ }
1157
1203
  function cellText(column, item) {
1158
1204
  const raw = column.display ? column.display(item) : column.value(item);
1159
1205
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
@@ -1274,6 +1320,21 @@ function RecordWorkspace({
1274
1320
  children: /* @__PURE__ */ jsx(DownloadIcon, {})
1275
1321
  }
1276
1322
  ) : null,
1323
+ showBulkImport ? /* @__PURE__ */ jsx(
1324
+ "button",
1325
+ {
1326
+ type: "button",
1327
+ className: "ghost side-rail-icon",
1328
+ title: "Bulk entry",
1329
+ "aria-label": "Bulk entry",
1330
+ disabled: importBusy,
1331
+ onClick: () => {
1332
+ setSideOpen(true);
1333
+ setBulkOpen(true);
1334
+ },
1335
+ children: /* @__PURE__ */ jsx(UploadIcon, {})
1336
+ }
1337
+ ) : null,
1277
1338
  showFilters ? /* @__PURE__ */ jsxs(
1278
1339
  "button",
1279
1340
  {
@@ -1398,6 +1459,77 @@ function RecordWorkspace({
1398
1459
  option.format
1399
1460
  )) }) : null
1400
1461
  ] }) : null,
1462
+ showBulkImport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk", children: [
1463
+ /* @__PURE__ */ jsxs(
1464
+ "button",
1465
+ {
1466
+ type: "button",
1467
+ className: "ghost side-rail-bulk-toggle",
1468
+ "aria-expanded": bulkOpen,
1469
+ disabled: importBusy,
1470
+ onClick: () => setBulkOpen((open) => !open),
1471
+ children: [
1472
+ /* @__PURE__ */ jsx(UploadIcon, {}),
1473
+ /* @__PURE__ */ jsx("span", { children: importBusy ? "Importing\u2026" : "Bulk entry" })
1474
+ ]
1475
+ }
1476
+ ),
1477
+ bulkOpen ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-panel", role: "group", "aria-label": "Bulk entry", children: [
1478
+ /* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-mode", children: [
1479
+ "Mode",
1480
+ /* @__PURE__ */ jsx(
1481
+ Select,
1482
+ {
1483
+ value: bulkMode,
1484
+ options: BULK_IMPORT_MODE_OPTIONS.map((option) => ({ value: option.mode, label: option.label })),
1485
+ onChange: (value) => setBulkMode(value)
1486
+ }
1487
+ )
1488
+ ] }),
1489
+ /* @__PURE__ */ jsxs("label", { className: "side-rail-bulk-file", children: [
1490
+ "File",
1491
+ /* @__PURE__ */ jsx(
1492
+ "input",
1493
+ {
1494
+ ref: bulkFileInputRef,
1495
+ type: "file",
1496
+ accept: ".csv,.xlsx,.json",
1497
+ disabled: importBusy,
1498
+ onChange: (event) => {
1499
+ setBulkFile(event.target.files?.[0] ?? null);
1500
+ setBulkReport(null);
1501
+ }
1502
+ }
1503
+ )
1504
+ ] }),
1505
+ /* @__PURE__ */ jsx(
1506
+ "button",
1507
+ {
1508
+ type: "button",
1509
+ className: "side-rail-bulk-submit",
1510
+ disabled: importBusy || !bulkFile,
1511
+ onClick: () => void submitBulkImport(),
1512
+ children: importBusy ? "Importing\u2026" : "Import"
1513
+ }
1514
+ ),
1515
+ bulkReport ? /* @__PURE__ */ jsxs("div", { className: "side-rail-bulk-report", role: "status", children: [
1516
+ /* @__PURE__ */ jsx("p", { children: bulkReport.applied ? `Applied ${bulkReport.totalRows} row(s).` : `${bulkReport.failed} error(s) in ${bulkReport.totalRows} row(s).` }),
1517
+ bulkReport.errors.length > 0 ? /* @__PURE__ */ jsxs("ul", { className: "side-rail-bulk-errors", children: [
1518
+ bulkReport.errors.slice(0, 8).map((error, index) => /* @__PURE__ */ jsxs("li", { children: [
1519
+ "Row ",
1520
+ error.row,
1521
+ ": ",
1522
+ error.message
1523
+ ] }, `${error.row}-${error.code}-${index}`)),
1524
+ bulkReport.errors.length > 8 ? /* @__PURE__ */ jsxs("li", { children: [
1525
+ "\u2026and ",
1526
+ bulkReport.errors.length - 8,
1527
+ " more"
1528
+ ] }) : null
1529
+ ] }) : null
1530
+ ] }) : null
1531
+ ] }) : null
1532
+ ] }) : null,
1401
1533
  showFilters ? /* @__PURE__ */ jsxs("div", { className: "side-rail-filters", children: [
1402
1534
  /* @__PURE__ */ jsxs("div", { className: "filter-panel-head", children: [
1403
1535
  /* @__PURE__ */ jsx("h3", { children: "Filters" }),