@burdenoff/microfe-assethandler 2026.703.4 → 2026.703.6

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.
Files changed (46) hide show
  1. package/dist/assethandler/AssetHandlerRoutes.js +16 -5
  2. package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
  3. package/dist/assethandler/components/ActivityTimeline.js +70 -0
  4. package/dist/assethandler/components/ActivityTimeline.js.map +1 -0
  5. package/dist/assethandler/components/AttachmentsPanel.js +204 -0
  6. package/dist/assethandler/components/AttachmentsPanel.js.map +1 -0
  7. package/dist/assethandler/components/CommentsPanel.js +137 -0
  8. package/dist/assethandler/components/CommentsPanel.js.map +1 -0
  9. package/dist/assethandler/components/NotFoundState.js +25 -0
  10. package/dist/assethandler/components/NotFoundState.js.map +1 -0
  11. package/dist/assethandler/components/Pagination.js +90 -0
  12. package/dist/assethandler/components/Pagination.js.map +1 -0
  13. package/dist/assethandler/components/index.js +5 -0
  14. package/dist/assethandler/pages/AnalyticsPage.js +398 -200
  15. package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
  16. package/dist/assethandler/pages/AssetsAssetCategoriesPage.js +62 -68
  17. package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
  18. package/dist/assethandler/pages/AssetsAssetCreatePage.js +158 -4
  19. package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
  20. package/dist/assethandler/pages/AssetsAssetDetailPage.js +685 -181
  21. package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
  22. package/dist/assethandler/pages/AssetsAssetListPage.js +184 -167
  23. package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
  24. package/dist/assethandler/pages/AssetsAssetTrackingPage.js +105 -134
  25. package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
  26. package/dist/assethandler/pages/FinanceBudgetDetailPage.js +272 -85
  27. package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
  28. package/dist/assethandler/pages/FinanceFinanceHubPage.js +602 -153
  29. package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
  30. package/dist/assethandler/pages/FinanceInvoiceDetailPage.js +139 -95
  31. package/dist/assethandler/pages/FinanceInvoiceDetailPage.js.map +1 -1
  32. package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js +269 -149
  33. package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
  34. package/dist/assethandler/pages/ReportsDashboardPage.js +530 -0
  35. package/dist/assethandler/pages/ReportsDashboardPage.js.map +1 -0
  36. package/dist/assethandler/pages/TransactionsTransactionDetailPage.js +216 -165
  37. package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
  38. package/dist/assethandler/pages/TransactionsTransactionListPage.js +157 -132
  39. package/dist/assethandler/pages/TransactionsTransactionListPage.js.map +1 -1
  40. package/dist/assethandler/providers/AssetHandlerProvider.js +24 -3
  41. package/dist/assethandler/providers/AssetHandlerProvider.js.map +1 -1
  42. package/dist/assethandler/store/assethandlerStore.js +28 -4
  43. package/dist/assethandler/store/assethandlerStore.js.map +1 -1
  44. package/dist/assethandler/utils/csv.js +16 -0
  45. package/dist/assethandler/utils/csv.js.map +1 -0
  46. package/package.json +1 -1
@@ -0,0 +1,25 @@
1
+ import { jsx as e, jsxs as t } from "react/jsx-runtime";
2
+ import { Button as n, IllustratedEmptyState as r } from "@burdenoff/fe-libs/ui";
3
+ //#region src/assethandler/components/NotFoundState.tsx
4
+ function i({ entityLabel: i, description: a, backLabel: o = "Go back", onBack: s, action: c }) {
5
+ return /* @__PURE__ */ e("div", {
6
+ className: "p-6",
7
+ children: /* @__PURE__ */ e(r, {
8
+ illustration: "empty-search",
9
+ title: `${i} not found`,
10
+ description: a ?? `This ${i.toLowerCase()} may have been removed, or the link is out of date. Head back to the list to find what you need.`,
11
+ action: /* @__PURE__ */ t("div", {
12
+ className: "flex items-center gap-2",
13
+ children: [s ? /* @__PURE__ */ e(n, {
14
+ size: "sm",
15
+ onClick: s,
16
+ children: o
17
+ }) : null, c]
18
+ })
19
+ })
20
+ });
21
+ }
22
+ //#endregion
23
+ export { i as NotFoundState };
24
+
25
+ //# sourceMappingURL=NotFoundState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotFoundState.js","names":[],"sources":["../../../src/assethandler/components/NotFoundState.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Button, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\n\n/**\n * Standard \"record not found\" panel for detail pages.\n *\n * Detail pages fetch a single record by id (e.g. `budget(id)`, `invoice(id)`).\n * When the by-id query returns `null` — a wrong/stale id, a cross-workspace id,\n * or a soft-deleted record — pages render this instead of silently falling back\n * to `array[0]` (the historic wrong-record bug). B2-2 detail pages reuse it.\n */\nexport interface NotFoundStateProps {\n /** What was not found, e.g. \"Invoice\", \"Work order\". */\n entityLabel: string;\n /** Optional override for the description line. */\n description?: string;\n /** Label for the primary action button. */\n backLabel?: string;\n /** Handler for the primary action (typically navigate back to the list). */\n onBack?: () => void;\n /** Optional extra action rendered next to the back button. */\n action?: ReactNode;\n}\n\nexport function NotFoundState({\n entityLabel,\n description,\n backLabel = 'Go back',\n onBack,\n action,\n}: NotFoundStateProps) {\n return (\n <div className=\"p-6\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title={`${entityLabel} not found`}\n description={\n description ??\n `This ${entityLabel.toLowerCase()} may have been removed, or the link is out of date. Head back to the list to find what you need.`\n }\n action={\n <div className=\"flex items-center gap-2\">\n {onBack ? (\n <Button size=\"sm\" onClick={onBack}>\n {backLabel}\n </Button>\n ) : null}\n {action}\n </div>\n }\n />\n </div>\n );\n}\n"],"mappings":";;;AAwBA,SAAgB,EAAc,EAC5B,gBACA,gBACA,eAAY,WACZ,WACA,aACqB;AACrB,QACE,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,GAAG,EAAY;GACtB,aACE,KACA,QAAQ,EAAY,aAAa,CAAC;GAEpC,QACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,IACC,kBAAC,GAAD;KAAQ,MAAK;KAAK,SAAS;eACxB;KACM,CAAA,GACP,MACH,EACG;;GAER,CAAA;EACE,CAAA"}
@@ -0,0 +1,90 @@
1
+ import { useMemo as e, useState as t } from "react";
2
+ import { ChevronLeft as n, ChevronRight as r } from "lucide-react";
3
+ import { jsx as i, jsxs as a } from "react/jsx-runtime";
4
+ import { Button as o } from "@burdenoff/fe-libs/ui";
5
+ //#region src/assethandler/components/Pagination.tsx
6
+ var s = 10;
7
+ function c(n, r = {}) {
8
+ let { pageSize: i = s, resetKey: a } = r, [o, c] = t(1), [l, u] = t(i), d = n.length, f = Math.max(1, Math.ceil(d / l)), p = e(() => Math.min(Math.max(1, o), f), [
9
+ o,
10
+ f,
11
+ a
12
+ ]), m = e(() => {
13
+ let e = (p - 1) * l;
14
+ return n.slice(e, e + l);
15
+ }, [
16
+ n,
17
+ p,
18
+ l
19
+ ]), h = d === 0 ? 0 : (p - 1) * l + 1, g = Math.min(p * l, d), _ = (e) => c(Math.min(Math.max(1, e), f));
20
+ return {
21
+ page: p,
22
+ pageSize: l,
23
+ pageCount: f,
24
+ pageItems: m,
25
+ totalItems: d,
26
+ rangeStart: h,
27
+ rangeEnd: g,
28
+ canPrev: p > 1,
29
+ canNext: p < f,
30
+ setPage: _,
31
+ nextPage: () => _(p + 1),
32
+ prevPage: () => _(p - 1),
33
+ setPageSize: (e) => {
34
+ u(e), c(1);
35
+ }
36
+ };
37
+ }
38
+ function l({ page: e, pageCount: t, rangeStart: s, rangeEnd: c, totalItems: l, canPrev: u, canNext: d, onPrev: f, onNext: p, itemLabel: m = "items", className: h }) {
39
+ return l === 0 ? null : /* @__PURE__ */ a("div", {
40
+ className: `flex flex-wrap items-center justify-between gap-3 pt-4 ${h ?? ""}`,
41
+ role: "navigation",
42
+ "aria-label": "Pagination",
43
+ children: [/* @__PURE__ */ a("p", {
44
+ className: "text-xs text-text-secondary tabular-nums",
45
+ children: [
46
+ "Showing ",
47
+ s,
48
+ "–",
49
+ c,
50
+ " of ",
51
+ l,
52
+ " ",
53
+ m
54
+ ]
55
+ }), /* @__PURE__ */ a("div", {
56
+ className: "flex items-center gap-2",
57
+ children: [
58
+ /* @__PURE__ */ a("span", {
59
+ className: "text-xs text-text-secondary tabular-nums",
60
+ children: [
61
+ "Page ",
62
+ e,
63
+ " of ",
64
+ t
65
+ ]
66
+ }),
67
+ /* @__PURE__ */ a(o, {
68
+ size: "sm",
69
+ variant: "outline",
70
+ onClick: f,
71
+ disabled: !u,
72
+ "aria-label": "Previous page",
73
+ children: [/* @__PURE__ */ i(n, { className: "h-4 w-4" }), "Prev"]
74
+ }),
75
+ /* @__PURE__ */ a(o, {
76
+ size: "sm",
77
+ variant: "outline",
78
+ onClick: p,
79
+ disabled: !d,
80
+ "aria-label": "Next page",
81
+ children: ["Next", /* @__PURE__ */ i(r, { className: "h-4 w-4" })]
82
+ })
83
+ ]
84
+ })]
85
+ });
86
+ }
87
+ //#endregion
88
+ export { l as Pagination, c as usePagination };
89
+
90
+ //# sourceMappingURL=Pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Pagination.js","names":[],"sources":["../../../src/assethandler/components/Pagination.tsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { ChevronLeft, ChevronRight } from 'lucide-react';\n\n/**\n * Cursor/limit pagination for AssetHandler lists.\n *\n * The product's bootstrap query hydrates full domain collections into the\n * store, so list pages paginate those arrays client-side with `usePagination`.\n * Server-backed register queries (assetRegister, maintenanceLog) accept\n * `AssetHandlerPaginationInput { cursor, limit }` — the `limit` here maps to\n * that input's page size and `page` drives the offset window.\n *\n * B2-2 pages import both `Pagination` and `usePagination` from the components\n * barrel so every list in the product shares one pagination contract.\n */\nexport interface AssetHandlerPaginationInput {\n cursor?: string | null;\n limit?: number;\n}\n\nexport interface UsePaginationResult<T> {\n page: number;\n pageSize: number;\n pageCount: number;\n pageItems: T[];\n totalItems: number;\n /** 1-based index of the first item on the current page (0 when empty). */\n rangeStart: number;\n /** 1-based index of the last item on the current page. */\n rangeEnd: number;\n canPrev: boolean;\n canNext: boolean;\n setPage: (page: number) => void;\n nextPage: () => void;\n prevPage: () => void;\n setPageSize: (size: number) => void;\n}\n\nexport interface UsePaginationOptions {\n pageSize?: number;\n /**\n * When this value changes (e.g. an active filter or search term), the current\n * page resets to 1 so the user is never stranded on an out-of-range page.\n */\n resetKey?: unknown;\n}\n\nconst DEFAULT_PAGE_SIZE = 10;\n\nexport function usePagination<T>(\n items: T[],\n options: UsePaginationOptions = {}\n): UsePaginationResult<T> {\n const { pageSize: initialPageSize = DEFAULT_PAGE_SIZE, resetKey } = options;\n const [page, setPageState] = useState(1);\n const [pageSize, setPageSizeState] = useState(initialPageSize);\n\n const totalItems = items.length;\n const pageCount = Math.max(1, Math.ceil(totalItems / pageSize));\n\n // Clamp the page into range whenever the dataset, page size, or resetKey shifts.\n const safePage = useMemo(() => {\n void resetKey;\n return Math.min(Math.max(1, page), pageCount);\n }, [page, pageCount, resetKey]);\n\n const pageItems = useMemo(() => {\n const start = (safePage - 1) * pageSize;\n return items.slice(start, start + pageSize);\n }, [items, safePage, pageSize]);\n\n const rangeStart = totalItems === 0 ? 0 : (safePage - 1) * pageSize + 1;\n const rangeEnd = Math.min(safePage * pageSize, totalItems);\n\n const setPage = (next: number) => setPageState(Math.min(Math.max(1, next), pageCount));\n const setPageSize = (size: number) => {\n setPageSizeState(size);\n setPageState(1);\n };\n\n return {\n page: safePage,\n pageSize,\n pageCount,\n pageItems,\n totalItems,\n rangeStart,\n rangeEnd,\n canPrev: safePage > 1,\n canNext: safePage < pageCount,\n setPage,\n nextPage: () => setPage(safePage + 1),\n prevPage: () => setPage(safePage - 1),\n setPageSize,\n };\n}\n\nexport interface PaginationProps {\n page: number;\n pageCount: number;\n rangeStart: number;\n rangeEnd: number;\n totalItems: number;\n canPrev: boolean;\n canNext: boolean;\n onPrev: () => void;\n onNext: () => void;\n /** Plural noun for the range label, e.g. \"assets\". Defaults to \"items\". */\n itemLabel?: string;\n className?: string;\n}\n\nexport function Pagination({\n page,\n pageCount,\n rangeStart,\n rangeEnd,\n totalItems,\n canPrev,\n canNext,\n onPrev,\n onNext,\n itemLabel = 'items',\n className,\n}: PaginationProps) {\n if (totalItems === 0) return null;\n\n return (\n <div\n className={`flex flex-wrap items-center justify-between gap-3 pt-4 ${className ?? ''}`}\n role=\"navigation\"\n aria-label=\"Pagination\"\n >\n <p className=\"text-xs text-text-secondary tabular-nums\">\n Showing {rangeStart}–{rangeEnd} of {totalItems} {itemLabel}\n </p>\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary tabular-nums\">\n Page {page} of {pageCount}\n </span>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={onPrev}\n disabled={!canPrev}\n aria-label=\"Previous page\"\n >\n <ChevronLeft className=\"h-4 w-4\" />\n Prev\n </Button>\n <Button\n size=\"sm\"\n variant=\"outline\"\n onClick={onNext}\n disabled={!canNext}\n aria-label=\"Next page\"\n >\n Next\n <ChevronRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;AAgDA,IAAM,IAAoB;AAE1B,SAAgB,EACd,GACA,IAAgC,EAAE,EACV;CACxB,IAAM,EAAE,UAAU,IAAkB,GAAmB,gBAAa,GAC9D,CAAC,GAAM,KAAgB,EAAS,EAAE,EAClC,CAAC,GAAU,KAAoB,EAAS,EAAgB,EAExD,IAAa,EAAM,QACnB,IAAY,KAAK,IAAI,GAAG,KAAK,KAAK,IAAa,EAAS,CAAC,EAGzD,IAAW,QAER,KAAK,IAAI,KAAK,IAAI,GAAG,EAAK,EAAE,EAAU,EAC5C;EAAC;EAAM;EAAW;EAAS,CAAC,EAEzB,IAAY,QAAc;EAC9B,IAAM,KAAS,IAAW,KAAK;AAC/B,SAAO,EAAM,MAAM,GAAO,IAAQ,EAAS;IAC1C;EAAC;EAAO;EAAU;EAAS,CAAC,EAEzB,IAAa,MAAe,IAAI,KAAK,IAAW,KAAK,IAAW,GAChE,IAAW,KAAK,IAAI,IAAW,GAAU,EAAW,EAEpD,KAAW,MAAiB,EAAa,KAAK,IAAI,KAAK,IAAI,GAAG,EAAK,EAAE,EAAU,CAAC;AAMtF,QAAO;EACL,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,IAAW;EACpB,SAAS,IAAW;EACpB;EACA,gBAAgB,EAAQ,IAAW,EAAE;EACrC,gBAAgB,EAAQ,IAAW,EAAE;EACrC,cAlBmB,MAAiB;AAEpC,GADA,EAAiB,EAAK,EACtB,EAAa,EAAE;;EAiBhB;;AAkBH,SAAgB,EAAW,EACzB,SACA,cACA,eACA,aACA,eACA,YACA,YACA,WACA,WACA,eAAY,SACZ,gBACkB;AAGlB,QAFI,MAAe,IAAU,OAG3B,kBAAC,OAAD;EACE,WAAW,0DAA0D,KAAa;EAClF,MAAK;EACL,cAAW;YAHb,CAKE,kBAAC,KAAD;GAAG,WAAU;aAAb;IAAwD;IAC7C;IAAW;IAAE;IAAS;IAAK;IAAW;IAAE;IAC/C;MACJ,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,QAAD;KAAM,WAAU;eAAhB;MAA2D;MACnD;MAAK;MAAK;MACX;;IACP,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,SAAS;KACT,UAAU,CAAC;KACX,cAAW;eALb,CAOE,kBAAC,GAAD,EAAa,WAAU,WAAY,CAAA,EAAA,OAE5B;;IACT,kBAAC,GAAD;KACE,MAAK;KACL,SAAQ;KACR,SAAS;KACT,UAAU,CAAC;KACX,cAAW;eALb,CAMC,QAEC,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,CAC7B;;IACL;KACF"}
@@ -0,0 +1,5 @@
1
+ import "./AttachmentsPanel.js";
2
+ import "./CommentsPanel.js";
3
+ import "./ActivityTimeline.js";
4
+ import "./Pagination.js";
5
+ import "./NotFoundState.js";