@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/aksui.css CHANGED
@@ -1222,7 +1222,8 @@ button.side-rail-add:hover {
1222
1222
  }
1223
1223
 
1224
1224
  .side-rail-columns,
1225
- .side-rail-download {
1225
+ .side-rail-download,
1226
+ .side-rail-bulk {
1226
1227
  display: grid;
1227
1228
  gap: 8px;
1228
1229
  }
@@ -1350,6 +1351,79 @@ button.side-rail-download-format:disabled {
1350
1351
  cursor: default;
1351
1352
  }
1352
1353
 
1354
+ button.side-rail-bulk-toggle {
1355
+ display: inline-flex;
1356
+ align-items: center;
1357
+ justify-content: center;
1358
+ gap: 8px;
1359
+ width: 100%;
1360
+ padding: 10px 12px;
1361
+ border: 1px solid var(--aks-border, #d7dde5);
1362
+ border-radius: var(--aks-radius);
1363
+ background: #fff;
1364
+ color: var(--aks-brand);
1365
+ box-shadow: none;
1366
+ }
1367
+
1368
+ button.side-rail-bulk-toggle svg {
1369
+ width: 18px;
1370
+ height: 18px;
1371
+ }
1372
+
1373
+ button.side-rail-bulk-toggle:hover:not(:disabled) {
1374
+ background: #f5f7fa;
1375
+ }
1376
+
1377
+ button.side-rail-bulk-toggle:disabled {
1378
+ opacity: 0.55;
1379
+ cursor: default;
1380
+ }
1381
+
1382
+ .side-rail-bulk-panel {
1383
+ display: grid;
1384
+ gap: 10px;
1385
+ padding: 8px;
1386
+ border: 1px solid var(--aks-line);
1387
+ border-radius: var(--aks-radius);
1388
+ background: #faf9f7;
1389
+ }
1390
+
1391
+ label.side-rail-bulk-mode,
1392
+ label.side-rail-bulk-file {
1393
+ display: grid;
1394
+ gap: 6px;
1395
+ margin: 0;
1396
+ font-size: 13px;
1397
+ font-weight: 600;
1398
+ color: var(--aks-brand);
1399
+ }
1400
+
1401
+ button.side-rail-bulk-submit {
1402
+ width: 100%;
1403
+ padding: 10px 12px;
1404
+ border: none;
1405
+ border-radius: var(--aks-radius);
1406
+ background: var(--aks-accent, #c45c26);
1407
+ color: #fff;
1408
+ font-weight: 600;
1409
+ box-shadow: none;
1410
+ }
1411
+
1412
+ button.side-rail-bulk-submit:disabled {
1413
+ opacity: 0.5;
1414
+ cursor: default;
1415
+ }
1416
+
1417
+ .side-rail-bulk-report {
1418
+ font-size: 12px;
1419
+ color: var(--aks-brand);
1420
+ }
1421
+
1422
+ .side-rail-bulk-errors {
1423
+ margin: 6px 0 0;
1424
+ padding-left: 18px;
1425
+ }
1426
+
1353
1427
  .side-rail-filters {
1354
1428
  display: grid;
1355
1429
  gap: 12px;
package/dist/index.cjs CHANGED
@@ -869,6 +869,11 @@ var EXPORT_FORMAT_OPTIONS = [
869
869
  { format: "xlsx", label: "Excel" },
870
870
  { format: "json", label: "JSON" }
871
871
  ];
872
+ var BULK_IMPORT_MODE_OPTIONS = [
873
+ { mode: "insert", label: "Insert" },
874
+ { mode: "update", label: "Update" },
875
+ { mode: "upsert", label: "Upsert" }
876
+ ];
872
877
  function defaultVisibleKeys(columns) {
873
878
  return columns.filter((column) => column.defaultVisible !== false).map((column) => column.key);
874
879
  }
@@ -945,6 +950,13 @@ function PreviewIcon() {
945
950
  /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "10", cy: "10", r: "2.4", fill: "none", stroke: "currentColor", strokeWidth: "1.6" })
946
951
  ] });
947
952
  }
953
+ function UploadIcon() {
954
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
955
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 16.5V7.3", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
956
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6.5 10.8 10 7.2l3.5 3.6", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }),
957
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4.5h12", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
958
+ ] });
959
+ }
948
960
  function DownloadIcon() {
949
961
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", children: [
950
962
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3.5v8.2", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }),
@@ -994,7 +1006,11 @@ function RecordWorkspace({
994
1006
  canDelete,
995
1007
  onDownload,
996
1008
  canDownload = true,
1009
+ canExport,
997
1010
  downloadBusy = false,
1011
+ onBulkImport,
1012
+ canImport = true,
1013
+ importBusy = false,
998
1014
  showColumnPicker = true,
999
1015
  columnPrefsKey,
1000
1016
  visibleColumnKeys,
@@ -1017,6 +1033,11 @@ function RecordWorkspace({
1017
1033
  const [sideOpen, setSideOpen] = react.useState(false);
1018
1034
  const [toolsDrawerOpen, setToolsDrawerOpen] = react.useState(false);
1019
1035
  const [downloadOpen, setDownloadOpen] = react.useState(false);
1036
+ const [bulkOpen, setBulkOpen] = react.useState(false);
1037
+ const [bulkMode, setBulkMode] = react.useState("upsert");
1038
+ const [bulkFile, setBulkFile] = react.useState(null);
1039
+ const [bulkReport, setBulkReport] = react.useState(null);
1040
+ const bulkFileInputRef = react.useRef(null);
1020
1041
  const [columnsOpen, setColumnsOpen] = react.useState(false);
1021
1042
  const [previewEnabled, setPreviewEnabled] = react.useState(false);
1022
1043
  const [previewKey, setPreviewKey] = react.useState(null);
@@ -1111,7 +1132,9 @@ function RecordWorkspace({
1111
1132
  const start = showAll ? 0 : (currentPage - 1) * numericPageSize;
1112
1133
  const pageItems = showAll ? sorted : sorted.slice(start, start + numericPageSize);
1113
1134
  const showAdd = canAdd && Boolean(onAdd);
1114
- const showDownload = Boolean(onDownload) && canDownload;
1135
+ const exportAllowed = (canExport ?? true) && canDownload;
1136
+ const showDownload = Boolean(onDownload) && exportAllowed;
1137
+ const showBulkImport = Boolean(onBulkImport) && canImport;
1115
1138
  const showFilters = filterableColumns.length > 0;
1116
1139
  const showColumns = showColumnPicker && columns.length > 0;
1117
1140
  const previewItem = previewKey === null ? null : sorted.find((item) => rowKey(item) === previewKey) ?? null;
@@ -1156,6 +1179,29 @@ function RecordWorkspace({
1156
1179
  onDownload(format, exportColumns);
1157
1180
  setDownloadOpen(false);
1158
1181
  }
1182
+ async function submitBulkImport() {
1183
+ if (!onBulkImport || importBusy || !bulkFile) {
1184
+ return;
1185
+ }
1186
+ setBulkReport(null);
1187
+ try {
1188
+ const report = await onBulkImport(bulkMode, bulkFile);
1189
+ setBulkReport(report);
1190
+ if (report.applied) {
1191
+ setBulkFile(null);
1192
+ if (bulkFileInputRef.current) {
1193
+ bulkFileInputRef.current.value = "";
1194
+ }
1195
+ }
1196
+ } catch {
1197
+ setBulkReport({
1198
+ totalRows: 0,
1199
+ failed: 1,
1200
+ applied: false,
1201
+ errors: [{ row: 0, code: "ImportFailed", message: "Import request failed." }]
1202
+ });
1203
+ }
1204
+ }
1159
1205
  function cellText(column, item) {
1160
1206
  const raw = column.display ? column.display(item) : column.value(item);
1161
1207
  return raw === null || raw === void 0 || raw === "" ? "\u2014" : String(raw);
@@ -1276,6 +1322,21 @@ function RecordWorkspace({
1276
1322
  children: /* @__PURE__ */ jsxRuntime.jsx(DownloadIcon, {})
1277
1323
  }
1278
1324
  ) : null,
1325
+ showBulkImport ? /* @__PURE__ */ jsxRuntime.jsx(
1326
+ "button",
1327
+ {
1328
+ type: "button",
1329
+ className: "ghost side-rail-icon",
1330
+ title: "Bulk entry",
1331
+ "aria-label": "Bulk entry",
1332
+ disabled: importBusy,
1333
+ onClick: () => {
1334
+ setSideOpen(true);
1335
+ setBulkOpen(true);
1336
+ },
1337
+ children: /* @__PURE__ */ jsxRuntime.jsx(UploadIcon, {})
1338
+ }
1339
+ ) : null,
1279
1340
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs(
1280
1341
  "button",
1281
1342
  {
@@ -1400,6 +1461,77 @@ function RecordWorkspace({
1400
1461
  option.format
1401
1462
  )) }) : null
1402
1463
  ] }) : null,
1464
+ showBulkImport ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-bulk", children: [
1465
+ /* @__PURE__ */ jsxRuntime.jsxs(
1466
+ "button",
1467
+ {
1468
+ type: "button",
1469
+ className: "ghost side-rail-bulk-toggle",
1470
+ "aria-expanded": bulkOpen,
1471
+ disabled: importBusy,
1472
+ onClick: () => setBulkOpen((open) => !open),
1473
+ children: [
1474
+ /* @__PURE__ */ jsxRuntime.jsx(UploadIcon, {}),
1475
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: importBusy ? "Importing\u2026" : "Bulk entry" })
1476
+ ]
1477
+ }
1478
+ ),
1479
+ bulkOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-bulk-panel", role: "group", "aria-label": "Bulk entry", children: [
1480
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "side-rail-bulk-mode", children: [
1481
+ "Mode",
1482
+ /* @__PURE__ */ jsxRuntime.jsx(
1483
+ Select,
1484
+ {
1485
+ value: bulkMode,
1486
+ options: BULK_IMPORT_MODE_OPTIONS.map((option) => ({ value: option.mode, label: option.label })),
1487
+ onChange: (value) => setBulkMode(value)
1488
+ }
1489
+ )
1490
+ ] }),
1491
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "side-rail-bulk-file", children: [
1492
+ "File",
1493
+ /* @__PURE__ */ jsxRuntime.jsx(
1494
+ "input",
1495
+ {
1496
+ ref: bulkFileInputRef,
1497
+ type: "file",
1498
+ accept: ".csv,.xlsx,.json",
1499
+ disabled: importBusy,
1500
+ onChange: (event) => {
1501
+ setBulkFile(event.target.files?.[0] ?? null);
1502
+ setBulkReport(null);
1503
+ }
1504
+ }
1505
+ )
1506
+ ] }),
1507
+ /* @__PURE__ */ jsxRuntime.jsx(
1508
+ "button",
1509
+ {
1510
+ type: "button",
1511
+ className: "side-rail-bulk-submit",
1512
+ disabled: importBusy || !bulkFile,
1513
+ onClick: () => void submitBulkImport(),
1514
+ children: importBusy ? "Importing\u2026" : "Import"
1515
+ }
1516
+ ),
1517
+ bulkReport ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-bulk-report", role: "status", children: [
1518
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: bulkReport.applied ? `Applied ${bulkReport.totalRows} row(s).` : `${bulkReport.failed} error(s) in ${bulkReport.totalRows} row(s).` }),
1519
+ bulkReport.errors.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "side-rail-bulk-errors", children: [
1520
+ bulkReport.errors.slice(0, 8).map((error, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1521
+ "Row ",
1522
+ error.row,
1523
+ ": ",
1524
+ error.message
1525
+ ] }, `${error.row}-${error.code}-${index}`)),
1526
+ bulkReport.errors.length > 8 ? /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1527
+ "\u2026and ",
1528
+ bulkReport.errors.length - 8,
1529
+ " more"
1530
+ ] }) : null
1531
+ ] }) : null
1532
+ ] }) : null
1533
+ ] }) : null
1534
+ ] }) : null,
1403
1535
  showFilters ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "side-rail-filters", children: [
1404
1536
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "filter-panel-head", children: [
1405
1537
  /* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Filters" }),