@nubitio/crud 0.5.1 → 0.5.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.cjs CHANGED
@@ -5315,6 +5315,11 @@ const ACTION_BADGE = {
5315
5315
  update: "info",
5316
5316
  delete: "danger"
5317
5317
  };
5318
+ const ACTION_TONE = {
5319
+ create: "success",
5320
+ update: "info",
5321
+ delete: "danger"
5322
+ };
5318
5323
  function formatAuditValue(value, yesLabel, noLabel) {
5319
5324
  if (value == null || value === "") return "—";
5320
5325
  if (typeof value === "boolean") return value ? yesLabel : noLabel;
@@ -5325,6 +5330,40 @@ function formatAuditValue(value, yesLabel, noLabel) {
5325
5330
  }
5326
5331
  return String(value);
5327
5332
  }
5333
+ function DefaultEntryContent({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5334
+ const changeKeys = Object.keys(entry.changes);
5335
+ if (changeKeys.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
5336
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5337
+ className: "nb-audit-trail__changes",
5338
+ children: changeKeys.map((field) => {
5339
+ const { before, after } = entry.changes[field];
5340
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5341
+ className: "nb-audit-trail__change",
5342
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5343
+ className: "nb-audit-trail__field",
5344
+ children: resolveFieldLabel(field)
5345
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5346
+ className: "nb-audit-trail__diff",
5347
+ children: [
5348
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5349
+ className: "nb-audit-trail__value nb-audit-trail__value--before",
5350
+ children: formatAuditValue(before, yesLabel, noLabel)
5351
+ }),
5352
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5353
+ className: "nb-audit-trail__arrow",
5354
+ "aria-hidden": "true",
5355
+ children: "→"
5356
+ }),
5357
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5358
+ className: "nb-audit-trail__value nb-audit-trail__value--after",
5359
+ children: formatAuditValue(after, yesLabel, noLabel)
5360
+ })
5361
+ ]
5362
+ })]
5363
+ }, field);
5364
+ })
5365
+ });
5366
+ }
5328
5367
  function DefaultEntryRenderer({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5329
5368
  const { t } = (0, _nubitio_core.useCoreTranslation)();
5330
5369
  const date = new Date(entry.timestamp);
@@ -5334,61 +5373,29 @@ function DefaultEntryRenderer({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5334
5373
  update: t("auditTrail.action.update"),
5335
5374
  delete: t("auditTrail.action.delete")
5336
5375
  };
5337
- const changeKeys = Object.keys(entry.changes);
5338
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5339
- className: `nb-audit-trail__entry nb-audit-trail__entry--${entry.action}`,
5340
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5341
- className: "nb-audit-trail__marker",
5342
- "aria-hidden": "true"
5343
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5376
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_nubitio_ui.TimelineItem, {
5377
+ status: "complete",
5378
+ tone: ACTION_TONE[entry.action],
5379
+ title: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5344
5380
  className: "nb-audit-trail__meta",
5345
- children: [
5346
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("time", {
5347
- className: "nb-audit-trail__timestamp",
5348
- dateTime: entry.timestamp,
5349
- children: formatted
5350
- }),
5351
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5352
- className: "nb-audit-trail__user",
5353
- children: entry.user
5354
- }),
5355
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_nubitio_ui.Badge, {
5356
- variant: ACTION_BADGE[entry.action],
5357
- size: "sm",
5358
- pill: true,
5359
- children: actionLabels[entry.action]
5360
- })
5361
- ]
5362
- }), changeKeys.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5363
- className: "nb-audit-trail__changes",
5364
- children: changeKeys.map((field) => {
5365
- const { before, after } = entry.changes[field];
5366
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
5367
- className: "nb-audit-trail__change",
5368
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5369
- className: "nb-audit-trail__field",
5370
- children: resolveFieldLabel(field)
5371
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5372
- className: "nb-audit-trail__diff",
5373
- children: [
5374
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5375
- className: "nb-audit-trail__value nb-audit-trail__value--before",
5376
- children: formatAuditValue(before, yesLabel, noLabel)
5377
- }),
5378
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5379
- className: "nb-audit-trail__arrow",
5380
- "aria-hidden": "true",
5381
- children: "→"
5382
- }),
5383
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5384
- className: "nb-audit-trail__value nb-audit-trail__value--after",
5385
- children: formatAuditValue(after, yesLabel, noLabel)
5386
- })
5387
- ]
5388
- })]
5389
- }, field);
5390
- })
5391
- })] })]
5381
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5382
+ className: "nb-audit-trail__user",
5383
+ children: entry.user
5384
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_nubitio_ui.Badge, {
5385
+ variant: ACTION_BADGE[entry.action],
5386
+ size: "sm",
5387
+ pill: true,
5388
+ children: actionLabels[entry.action]
5389
+ })]
5390
+ }),
5391
+ timestamp: formatted,
5392
+ dateTime: entry.timestamp,
5393
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultEntryContent, {
5394
+ entry,
5395
+ resolveFieldLabel,
5396
+ yesLabel,
5397
+ noLabel
5398
+ })
5392
5399
  });
5393
5400
  }
5394
5401
  function AuditTrailSkeleton() {
@@ -5475,12 +5482,10 @@ function AuditTrailPanel({ url, renderEntry, visible, onClose, recordSubtitle, r
5475
5482
  description: t("auditTrail.emptyHint"),
5476
5483
  size: "sm"
5477
5484
  });
5478
- if (fetchState.status === "success") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
5479
- className: "nb-audit-trail__timeline",
5480
- children: fetchState.entries.map((entry) => renderEntry ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
5481
- className: "nb-audit-trail__entry",
5482
- children: renderEntry(entry)
5483
- }, String(entry.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultEntryRenderer, {
5485
+ if (fetchState.status === "success") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_nubitio_ui.Timeline, {
5486
+ variant: "log",
5487
+ "aria-label": t("auditTrail.title"),
5488
+ children: fetchState.entries.map((entry) => renderEntry ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: renderEntry(entry) }, String(entry.id)) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultEntryRenderer, {
5484
5489
  entry,
5485
5490
  resolveFieldLabel,
5486
5491
  yesLabel,
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import React, { createContext, forwardRef, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
2
2
  import { Route, useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom";
3
3
  import { createPortal } from "react-dom";
4
- import { AppDialog, AppDropdown, Badge, Button, ConfirmDialog, DatePicker, DateRangePicker, Drawer, EmptyState, IconButton, Skeleton } from "@nubitio/ui";
4
+ import { AppDialog, AppDropdown, Badge, Button, ConfirmDialog, DatePicker, DateRangePicker, Drawer, EmptyState, IconButton, Skeleton, Timeline, TimelineItem } from "@nubitio/ui";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { createCrudEvents, createScopedEventBus, getCoreCurrency, getCoreLocale, getCoreTimezone, useCoreHttpClient, useCoreRuntime, useCoreTranslation, useEvents, useMercureSubscription } from "@nubitio/core";
7
7
  import { useDropzone } from "react-dropzone";
@@ -5291,6 +5291,11 @@ const ACTION_BADGE = {
5291
5291
  update: "info",
5292
5292
  delete: "danger"
5293
5293
  };
5294
+ const ACTION_TONE = {
5295
+ create: "success",
5296
+ update: "info",
5297
+ delete: "danger"
5298
+ };
5294
5299
  function formatAuditValue(value, yesLabel, noLabel) {
5295
5300
  if (value == null || value === "") return "—";
5296
5301
  if (typeof value === "boolean") return value ? yesLabel : noLabel;
@@ -5301,6 +5306,40 @@ function formatAuditValue(value, yesLabel, noLabel) {
5301
5306
  }
5302
5307
  return String(value);
5303
5308
  }
5309
+ function DefaultEntryContent({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5310
+ const changeKeys = Object.keys(entry.changes);
5311
+ if (changeKeys.length === 0) return /* @__PURE__ */ jsx(Fragment, {});
5312
+ return /* @__PURE__ */ jsx("ul", {
5313
+ className: "nb-audit-trail__changes",
5314
+ children: changeKeys.map((field) => {
5315
+ const { before, after } = entry.changes[field];
5316
+ return /* @__PURE__ */ jsxs("li", {
5317
+ className: "nb-audit-trail__change",
5318
+ children: [/* @__PURE__ */ jsx("span", {
5319
+ className: "nb-audit-trail__field",
5320
+ children: resolveFieldLabel(field)
5321
+ }), /* @__PURE__ */ jsxs("div", {
5322
+ className: "nb-audit-trail__diff",
5323
+ children: [
5324
+ /* @__PURE__ */ jsx("span", {
5325
+ className: "nb-audit-trail__value nb-audit-trail__value--before",
5326
+ children: formatAuditValue(before, yesLabel, noLabel)
5327
+ }),
5328
+ /* @__PURE__ */ jsx("span", {
5329
+ className: "nb-audit-trail__arrow",
5330
+ "aria-hidden": "true",
5331
+ children: "→"
5332
+ }),
5333
+ /* @__PURE__ */ jsx("span", {
5334
+ className: "nb-audit-trail__value nb-audit-trail__value--after",
5335
+ children: formatAuditValue(after, yesLabel, noLabel)
5336
+ })
5337
+ ]
5338
+ })]
5339
+ }, field);
5340
+ })
5341
+ });
5342
+ }
5304
5343
  function DefaultEntryRenderer({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5305
5344
  const { t } = useCoreTranslation();
5306
5345
  const date = new Date(entry.timestamp);
@@ -5310,61 +5349,29 @@ function DefaultEntryRenderer({ entry, resolveFieldLabel, yesLabel, noLabel }) {
5310
5349
  update: t("auditTrail.action.update"),
5311
5350
  delete: t("auditTrail.action.delete")
5312
5351
  };
5313
- const changeKeys = Object.keys(entry.changes);
5314
- return /* @__PURE__ */ jsxs("li", {
5315
- className: `nb-audit-trail__entry nb-audit-trail__entry--${entry.action}`,
5316
- children: [/* @__PURE__ */ jsx("span", {
5317
- className: "nb-audit-trail__marker",
5318
- "aria-hidden": "true"
5319
- }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
5352
+ return /* @__PURE__ */ jsx(TimelineItem, {
5353
+ status: "complete",
5354
+ tone: ACTION_TONE[entry.action],
5355
+ title: /* @__PURE__ */ jsxs("span", {
5320
5356
  className: "nb-audit-trail__meta",
5321
- children: [
5322
- /* @__PURE__ */ jsx("time", {
5323
- className: "nb-audit-trail__timestamp",
5324
- dateTime: entry.timestamp,
5325
- children: formatted
5326
- }),
5327
- /* @__PURE__ */ jsx("span", {
5328
- className: "nb-audit-trail__user",
5329
- children: entry.user
5330
- }),
5331
- /* @__PURE__ */ jsx(Badge, {
5332
- variant: ACTION_BADGE[entry.action],
5333
- size: "sm",
5334
- pill: true,
5335
- children: actionLabels[entry.action]
5336
- })
5337
- ]
5338
- }), changeKeys.length > 0 && /* @__PURE__ */ jsx("ul", {
5339
- className: "nb-audit-trail__changes",
5340
- children: changeKeys.map((field) => {
5341
- const { before, after } = entry.changes[field];
5342
- return /* @__PURE__ */ jsxs("li", {
5343
- className: "nb-audit-trail__change",
5344
- children: [/* @__PURE__ */ jsx("span", {
5345
- className: "nb-audit-trail__field",
5346
- children: resolveFieldLabel(field)
5347
- }), /* @__PURE__ */ jsxs("div", {
5348
- className: "nb-audit-trail__diff",
5349
- children: [
5350
- /* @__PURE__ */ jsx("span", {
5351
- className: "nb-audit-trail__value nb-audit-trail__value--before",
5352
- children: formatAuditValue(before, yesLabel, noLabel)
5353
- }),
5354
- /* @__PURE__ */ jsx("span", {
5355
- className: "nb-audit-trail__arrow",
5356
- "aria-hidden": "true",
5357
- children: "→"
5358
- }),
5359
- /* @__PURE__ */ jsx("span", {
5360
- className: "nb-audit-trail__value nb-audit-trail__value--after",
5361
- children: formatAuditValue(after, yesLabel, noLabel)
5362
- })
5363
- ]
5364
- })]
5365
- }, field);
5366
- })
5367
- })] })]
5357
+ children: [/* @__PURE__ */ jsx("span", {
5358
+ className: "nb-audit-trail__user",
5359
+ children: entry.user
5360
+ }), /* @__PURE__ */ jsx(Badge, {
5361
+ variant: ACTION_BADGE[entry.action],
5362
+ size: "sm",
5363
+ pill: true,
5364
+ children: actionLabels[entry.action]
5365
+ })]
5366
+ }),
5367
+ timestamp: formatted,
5368
+ dateTime: entry.timestamp,
5369
+ children: /* @__PURE__ */ jsx(DefaultEntryContent, {
5370
+ entry,
5371
+ resolveFieldLabel,
5372
+ yesLabel,
5373
+ noLabel
5374
+ })
5368
5375
  });
5369
5376
  }
5370
5377
  function AuditTrailSkeleton() {
@@ -5451,12 +5458,10 @@ function AuditTrailPanel({ url, renderEntry, visible, onClose, recordSubtitle, r
5451
5458
  description: t("auditTrail.emptyHint"),
5452
5459
  size: "sm"
5453
5460
  });
5454
- if (fetchState.status === "success") return /* @__PURE__ */ jsx("ul", {
5455
- className: "nb-audit-trail__timeline",
5456
- children: fetchState.entries.map((entry) => renderEntry ? /* @__PURE__ */ jsx("li", {
5457
- className: "nb-audit-trail__entry",
5458
- children: renderEntry(entry)
5459
- }, String(entry.id)) : /* @__PURE__ */ jsx(DefaultEntryRenderer, {
5461
+ if (fetchState.status === "success") return /* @__PURE__ */ jsx(Timeline, {
5462
+ variant: "log",
5463
+ "aria-label": t("auditTrail.title"),
5464
+ children: fetchState.entries.map((entry) => renderEntry ? /* @__PURE__ */ jsx(React.Fragment, { children: renderEntry(entry) }, String(entry.id)) : /* @__PURE__ */ jsx(DefaultEntryRenderer, {
5460
5465
  entry,
5461
5466
  resolveFieldLabel,
5462
5467
  yesLabel,
package/dist/style.css CHANGED
@@ -3305,61 +3305,6 @@ html[data-density=compact] .nb-crud-page-shell__footer {
3305
3305
  margin: calc(var(--space-1) * -1) 0 0;
3306
3306
  }
3307
3307
 
3308
- .nb-audit-trail__timeline {
3309
- display: flex;
3310
- flex-direction: column;
3311
- gap: 0;
3312
- list-style: none;
3313
- margin: 0;
3314
- padding: 0;
3315
- }
3316
-
3317
- .nb-audit-trail__entry {
3318
- display: grid;
3319
- gap: var(--space-2);
3320
- grid-template-columns: 12px 1fr;
3321
- padding: var(--space-3) 0;
3322
- position: relative;
3323
- }
3324
- .nb-audit-trail__entry:not(:last-child) {
3325
- border-bottom: 1px solid var(--border-color);
3326
- }
3327
- .nb-audit-trail__entry::before {
3328
- background: var(--border-color);
3329
- bottom: 0;
3330
- content: "";
3331
- left: 5px;
3332
- position: absolute;
3333
- top: calc(var(--space-3) + 6px);
3334
- width: 2px;
3335
- }
3336
- .nb-audit-trail__entry:last-child::before {
3337
- display: none;
3338
- }
3339
-
3340
- .nb-audit-trail__marker {
3341
- background: var(--surface-2);
3342
- border: 2px solid var(--accent-color);
3343
- border-radius: 50%;
3344
- height: 12px;
3345
- margin-top: 4px;
3346
- position: relative;
3347
- width: 12px;
3348
- z-index: 1;
3349
- }
3350
-
3351
- .nb-audit-trail__entry--create .nb-audit-trail__marker {
3352
- border-color: var(--success-color);
3353
- }
3354
-
3355
- .nb-audit-trail__entry--update .nb-audit-trail__marker {
3356
- border-color: var(--info-color, var(--accent-color));
3357
- }
3358
-
3359
- .nb-audit-trail__entry--delete .nb-audit-trail__marker {
3360
- border-color: var(--danger-color);
3361
- }
3362
-
3363
3308
  .nb-audit-trail__meta {
3364
3309
  align-items: center;
3365
3310
  display: flex;
@@ -3367,12 +3312,6 @@ html[data-density=compact] .nb-crud-page-shell__footer {
3367
3312
  gap: var(--space-2);
3368
3313
  }
3369
3314
 
3370
- .nb-audit-trail__timestamp {
3371
- color: var(--text-secondary);
3372
- font-size: var(--font-size-xs, 0.75rem);
3373
- font-variant-numeric: tabular-nums;
3374
- }
3375
-
3376
3315
  .nb-audit-trail__user {
3377
3316
  color: var(--text-primary);
3378
3317
  font-size: var(--font-size-sm, 0.8125rem);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nubitio/crud",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "type": "module",
5
5
  "description": "Declarative CRUD engine with field DSL, forms, datagrids, RBAC, conditional logic and pluggable adapters (Hydra/REST).",
6
6
  "license": "MIT",
@@ -56,8 +56,8 @@
56
56
  "react-dom": "^19.0.0",
57
57
  "react-i18next": "^14.0.0",
58
58
  "react-router-dom": "^6.0.0",
59
- "@nubitio/core": "^0.5.1",
60
- "@nubitio/ui": "^0.5.1"
59
+ "@nubitio/core": "^0.5.2",
60
+ "@nubitio/ui": "^0.5.2"
61
61
  },
62
62
  "dependencies": {
63
63
  "react-dropzone": "^15.0.0"