@open-mercato/core 0.6.8-develop.7042.1.413df59570 → 0.6.8-develop.7043.1.b0199a62c6
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.
|
@@ -24,8 +24,8 @@ function renderValue(value, fallback) {
|
|
|
24
24
|
if (typeof value === "boolean") return /* @__PURE__ */ jsx("span", { children: value ? "true" : "false" });
|
|
25
25
|
if (typeof value === "number" || typeof value === "bigint") return /* @__PURE__ */ jsx("span", { children: String(value) });
|
|
26
26
|
if (value instanceof Date) return /* @__PURE__ */ jsx("span", { children: value.toISOString() });
|
|
27
|
-
if (typeof value === "string") return /* @__PURE__ */ jsx("span", { className: "
|
|
28
|
-
return /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-y-auto whitespace-pre-wrap
|
|
27
|
+
if (typeof value === "string") return /* @__PURE__ */ jsx("span", { className: "wrap-anywhere", children: value });
|
|
28
|
+
return /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-y-auto whitespace-pre-wrap wrap-anywhere rounded-md bg-muted/50 px-2 py-1 text-xs leading-5 text-muted-foreground", children: safeStringify(value) });
|
|
29
29
|
}
|
|
30
30
|
function safeStringify(value) {
|
|
31
31
|
if (typeof value === "string") return value;
|
|
@@ -48,20 +48,28 @@ function formatDate(value) {
|
|
|
48
48
|
}).format(date);
|
|
49
49
|
}
|
|
50
50
|
function ChangedFieldsTable({ changeRows, noneLabel, t, beforeLabel, afterLabel }) {
|
|
51
|
+
const beforeHeading = beforeLabel ?? t("audit_logs.actions.details.before");
|
|
52
|
+
const afterHeading = afterLabel ?? t("audit_logs.actions.details.after");
|
|
51
53
|
return /* @__PURE__ */ jsxs("section", { children: [
|
|
52
54
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: t("audit_logs.actions.details.changed_fields") }),
|
|
53
|
-
changeRows.length ? /* @__PURE__ */ jsx("div", { className: "mt-2 overflow-x-auto rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "
|
|
54
|
-
/* @__PURE__ */ jsx("thead", { className: "bg-muted/50", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
55
|
+
changeRows.length ? /* @__PURE__ */ jsx("div", { className: "@container/changes mt-2", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "block w-full divide-y text-sm @lg/changes:table @lg/changes:min-w-full", children: [
|
|
56
|
+
/* @__PURE__ */ jsx("thead", { className: "hidden bg-muted/50 @lg/changes:table-header-group", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
55
57
|
/* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-left font-medium text-muted-foreground", children: t("audit_logs.actions.details.field") }),
|
|
56
|
-
/* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-left font-medium text-muted-foreground", children:
|
|
57
|
-
/* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-left font-medium text-muted-foreground", children:
|
|
58
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-left font-medium text-muted-foreground", children: beforeHeading }),
|
|
59
|
+
/* @__PURE__ */ jsx("th", { scope: "col", className: "px-4 py-2 text-left font-medium text-muted-foreground", children: afterHeading })
|
|
58
60
|
] }) }),
|
|
59
|
-
/* @__PURE__ */ jsx("tbody", { className: "divide-y", children: changeRows.map((row) => /* @__PURE__ */ jsxs("tr", { className: "align-top", children: [
|
|
60
|
-
/* @__PURE__ */ jsx("td", { className: "px-4 py-2 align-top
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
|
|
61
|
+
/* @__PURE__ */ jsx("tbody", { className: "block divide-y @lg/changes:table-row-group", children: changeRows.map((row) => /* @__PURE__ */ jsxs("tr", { className: "block px-4 py-3 align-top @lg/changes:table-row @lg/changes:p-0", children: [
|
|
62
|
+
/* @__PURE__ */ jsx("td", { className: "block font-medium @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2 @lg/changes:align-top", children: humanizeField(normalizeChangeField(row.field)) }),
|
|
63
|
+
/* @__PURE__ */ jsxs("td", { className: "mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2", children: [
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: "mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden", children: beforeHeading }),
|
|
65
|
+
renderValue(row.from, noneLabel)
|
|
66
|
+
] }),
|
|
67
|
+
/* @__PURE__ */ jsxs("td", { className: "mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2", children: [
|
|
68
|
+
/* @__PURE__ */ jsx("span", { className: "mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden", children: afterHeading }),
|
|
69
|
+
renderValue(row.to, noneLabel)
|
|
70
|
+
] })
|
|
63
71
|
] }, row.field)) })
|
|
64
|
-
] }) }) : /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: t("audit_logs.actions.details.no_changes") })
|
|
72
|
+
] }) }) }) : /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: t("audit_logs.actions.details.no_changes") })
|
|
65
73
|
] });
|
|
66
74
|
}
|
|
67
75
|
const DEFAULT_TRUNCATE_AT = 5e3;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/audit_logs/lib/display-helpers.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport type { ChangeRow } from './changeRows'\nimport { isRecord } from './changeRows'\nexport { extractChangeRows, isRecord } from './changeRows'\nexport type { ChangeRow } from './changeRows'\n\nexport function humanizeField(field: string) {\n return field\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/\\b\\w/g, (s) => s.toUpperCase())\n}\n\nexport function normalizeChangeField(field: string) {\n const parts = field.split('.')\n const base = parts.length === 2 ? parts[1] : field\n if (base.startsWith('cf_')) return base.slice(3)\n if (base.startsWith('cf:')) return base.slice(3)\n return base\n}\n\nexport function renderValue(value: unknown, fallback: string) {\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{fallback}</span>\n }\n if (typeof value === 'boolean') return <span>{value ? 'true' : 'false'}</span>\n if (typeof value === 'number' || typeof value === 'bigint') return <span>{String(value)}</span>\n if (value instanceof Date) return <span>{value.toISOString()}</span>\n if (typeof value === 'string') return <span className=\"
|
|
5
|
-
"mappings": "AA8BW,
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport {\n Accordion,\n AccordionContent,\n AccordionItem,\n AccordionTrigger,\n} from '@open-mercato/ui/primitives/accordion'\nimport type { ChangeRow } from './changeRows'\nimport { isRecord } from './changeRows'\nexport { extractChangeRows, isRecord } from './changeRows'\nexport type { ChangeRow } from './changeRows'\n\nexport function humanizeField(field: string) {\n return field\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/\\b\\w/g, (s) => s.toUpperCase())\n}\n\nexport function normalizeChangeField(field: string) {\n const parts = field.split('.')\n const base = parts.length === 2 ? parts[1] : field\n if (base.startsWith('cf_')) return base.slice(3)\n if (base.startsWith('cf:')) return base.slice(3)\n return base\n}\n\nexport function renderValue(value: unknown, fallback: string) {\n if (value === undefined || value === null || value === '') {\n return <span className=\"text-muted-foreground\">{fallback}</span>\n }\n if (typeof value === 'boolean') return <span>{value ? 'true' : 'false'}</span>\n if (typeof value === 'number' || typeof value === 'bigint') return <span>{String(value)}</span>\n if (value instanceof Date) return <span>{value.toISOString()}</span>\n if (typeof value === 'string') return <span className=\"wrap-anywhere\">{value}</span>\n return (\n <pre className=\"max-h-40 overflow-y-auto whitespace-pre-wrap wrap-anywhere rounded-md bg-muted/50 px-2 py-1 text-xs leading-5 text-muted-foreground\">\n {safeStringify(value)}\n </pre>\n )\n}\n\nexport function safeStringify(value: unknown) {\n if (typeof value === 'string') return value\n try {\n return JSON.stringify(value, null, 2)\n } catch {\n return String(value)\n }\n}\n\nexport function formatResource(\n item: { resourceKind: string | null; resourceId: string | null },\n fallback: string,\n) {\n if (!item.resourceKind && !item.resourceId) return fallback\n return [item.resourceKind, item.resourceId].filter(Boolean).join(' \u00B7 ')\n}\n\nexport function formatDate(value: string) {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date)\n}\n\nexport type ChangedFieldsTableProps = {\n changeRows: ChangeRow[]\n noneLabel: string\n t: TranslateFn\n beforeLabel?: string\n afterLabel?: string\n}\n\nexport function ChangedFieldsTable({ changeRows, noneLabel, t, beforeLabel, afterLabel }: ChangedFieldsTableProps) {\n const beforeHeading = beforeLabel ?? t('audit_logs.actions.details.before')\n const afterHeading = afterLabel ?? t('audit_logs.actions.details.after')\n return (\n <section>\n <h3 className=\"text-sm font-semibold\">\n {t('audit_logs.actions.details.changed_fields')}\n </h3>\n {changeRows.length ? (\n <div className=\"@container/changes mt-2\">\n <div className=\"overflow-x-auto rounded-lg border\">\n <table className=\"block w-full divide-y text-sm @lg/changes:table @lg/changes:min-w-full\">\n <thead className=\"hidden bg-muted/50 @lg/changes:table-header-group\">\n <tr>\n <th scope=\"col\" className=\"px-4 py-2 text-left font-medium text-muted-foreground\">\n {t('audit_logs.actions.details.field')}\n </th>\n <th scope=\"col\" className=\"px-4 py-2 text-left font-medium text-muted-foreground\">\n {beforeHeading}\n </th>\n <th scope=\"col\" className=\"px-4 py-2 text-left font-medium text-muted-foreground\">\n {afterHeading}\n </th>\n </tr>\n </thead>\n <tbody className=\"block divide-y @lg/changes:table-row-group\">\n {changeRows.map((row) => (\n <tr key={row.field} className=\"block px-4 py-3 align-top @lg/changes:table-row @lg/changes:p-0\">\n <td className=\"block font-medium @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2 @lg/changes:align-top\">\n {humanizeField(normalizeChangeField(row.field))}\n </td>\n <td className=\"mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2\">\n <span className=\"mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden\">\n {beforeHeading}\n </span>\n {renderValue(row.from, noneLabel)}\n </td>\n <td className=\"mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2\">\n <span className=\"mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden\">\n {afterHeading}\n </span>\n {renderValue(row.to, noneLabel)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n ) : (\n <p className=\"mt-2 text-sm text-muted-foreground\">\n {t('audit_logs.actions.details.no_changes')}\n </p>\n )}\n </section>\n )\n}\n\nexport type CollapsibleJsonSectionProps = {\n label: string\n value: unknown\n truncateAt?: number\n}\n\nconst DEFAULT_TRUNCATE_AT = 5000\n\nconst COLLAPSIBLE_JSON_ITEM_VALUE = 'open'\n\nexport function CollapsibleJsonSection({ label, value, truncateAt = DEFAULT_TRUNCATE_AT }: CollapsibleJsonSectionProps) {\n const [openValue, setOpenValue] = React.useState<string>('')\n const [showFull, setShowFull] = React.useState(false)\n\n const isOpen = openValue === COLLAPSIBLE_JSON_ITEM_VALUE\n const stringified = React.useMemo(() => (isOpen ? safeStringify(value) : ''), [isOpen, value])\n const isTruncated = stringified.length > truncateAt\n const displayText = !showFull && isTruncated ? stringified.slice(0, truncateAt) : stringified\n\n return (\n <Accordion type=\"single\" collapsible value={openValue} onValueChange={setOpenValue}>\n <AccordionItem value={COLLAPSIBLE_JSON_ITEM_VALUE}>\n <AccordionTrigger>\n <span className=\"font-semibold text-foreground group-data-[state=open]/accordion-trigger:text-primary\">\n {label}\n </span>\n </AccordionTrigger>\n <AccordionContent>\n <pre className=\"max-h-96 overflow-auto whitespace-pre-wrap break-words text-xs leading-5 text-muted-foreground\">\n {displayText}\n {!showFull && isTruncated ? '\\n\u2026' : null}\n </pre>\n {isTruncated ? (\n <button\n type=\"button\"\n className=\"mt-1 text-xs text-primary hover:underline\"\n onClick={() => setShowFull((prev) => !prev)}\n >\n {showFull ? 'Show less' : `Show all (${Math.ceil(stringified.length / 1024)} KB)`}\n </button>\n ) : null}\n </AccordionContent>\n </AccordionItem>\n </Accordion>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["isRecord"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7043.1.b0199a62c6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -252,16 +252,16 @@
|
|
|
252
252
|
"zod": "^4.4.3"
|
|
253
253
|
},
|
|
254
254
|
"peerDependencies": {
|
|
255
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
256
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
257
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
255
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7043.1.b0199a62c6",
|
|
256
|
+
"@open-mercato/shared": "0.6.8-develop.7043.1.b0199a62c6",
|
|
257
|
+
"@open-mercato/ui": "0.6.8-develop.7043.1.b0199a62c6",
|
|
258
258
|
"react": "^19.0.0",
|
|
259
259
|
"react-dom": "^19.0.0"
|
|
260
260
|
},
|
|
261
261
|
"devDependencies": {
|
|
262
|
-
"@open-mercato/ai-assistant": "0.6.8-develop.
|
|
263
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
264
|
-
"@open-mercato/ui": "0.6.8-develop.
|
|
262
|
+
"@open-mercato/ai-assistant": "0.6.8-develop.7043.1.b0199a62c6",
|
|
263
|
+
"@open-mercato/shared": "0.6.8-develop.7043.1.b0199a62c6",
|
|
264
|
+
"@open-mercato/ui": "0.6.8-develop.7043.1.b0199a62c6",
|
|
265
265
|
"@testing-library/dom": "^10.4.1",
|
|
266
266
|
"@testing-library/jest-dom": "^7.0.0",
|
|
267
267
|
"@testing-library/react": "^16.3.1",
|
|
@@ -33,9 +33,9 @@ export function renderValue(value: unknown, fallback: string) {
|
|
|
33
33
|
if (typeof value === 'boolean') return <span>{value ? 'true' : 'false'}</span>
|
|
34
34
|
if (typeof value === 'number' || typeof value === 'bigint') return <span>{String(value)}</span>
|
|
35
35
|
if (value instanceof Date) return <span>{value.toISOString()}</span>
|
|
36
|
-
if (typeof value === 'string') return <span className="
|
|
36
|
+
if (typeof value === 'string') return <span className="wrap-anywhere">{value}</span>
|
|
37
37
|
return (
|
|
38
|
-
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap
|
|
38
|
+
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap wrap-anywhere rounded-md bg-muted/50 px-2 py-1 text-xs leading-5 text-muted-foreground">
|
|
39
39
|
{safeStringify(value)}
|
|
40
40
|
</pre>
|
|
41
41
|
)
|
|
@@ -76,43 +76,53 @@ export type ChangedFieldsTableProps = {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export function ChangedFieldsTable({ changeRows, noneLabel, t, beforeLabel, afterLabel }: ChangedFieldsTableProps) {
|
|
79
|
+
const beforeHeading = beforeLabel ?? t('audit_logs.actions.details.before')
|
|
80
|
+
const afterHeading = afterLabel ?? t('audit_logs.actions.details.after')
|
|
79
81
|
return (
|
|
80
82
|
<section>
|
|
81
83
|
<h3 className="text-sm font-semibold">
|
|
82
84
|
{t('audit_logs.actions.details.changed_fields')}
|
|
83
85
|
</h3>
|
|
84
86
|
{changeRows.length ? (
|
|
85
|
-
<div className="mt-2
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
<
|
|
89
|
-
<
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
</thead>
|
|
100
|
-
<tbody className="divide-y">
|
|
101
|
-
{changeRows.map((row) => (
|
|
102
|
-
<tr key={row.field} className="align-top">
|
|
103
|
-
<td className="px-4 py-2 align-top font-medium">
|
|
104
|
-
{humanizeField(normalizeChangeField(row.field))}
|
|
105
|
-
</td>
|
|
106
|
-
<td className="px-4 py-2">
|
|
107
|
-
{renderValue(row.from, noneLabel)}
|
|
108
|
-
</td>
|
|
109
|
-
<td className="px-4 py-2">
|
|
110
|
-
{renderValue(row.to, noneLabel)}
|
|
111
|
-
</td>
|
|
87
|
+
<div className="@container/changes mt-2">
|
|
88
|
+
<div className="overflow-x-auto rounded-lg border">
|
|
89
|
+
<table className="block w-full divide-y text-sm @lg/changes:table @lg/changes:min-w-full">
|
|
90
|
+
<thead className="hidden bg-muted/50 @lg/changes:table-header-group">
|
|
91
|
+
<tr>
|
|
92
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
93
|
+
{t('audit_logs.actions.details.field')}
|
|
94
|
+
</th>
|
|
95
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
96
|
+
{beforeHeading}
|
|
97
|
+
</th>
|
|
98
|
+
<th scope="col" className="px-4 py-2 text-left font-medium text-muted-foreground">
|
|
99
|
+
{afterHeading}
|
|
100
|
+
</th>
|
|
112
101
|
</tr>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
</thead>
|
|
103
|
+
<tbody className="block divide-y @lg/changes:table-row-group">
|
|
104
|
+
{changeRows.map((row) => (
|
|
105
|
+
<tr key={row.field} className="block px-4 py-3 align-top @lg/changes:table-row @lg/changes:p-0">
|
|
106
|
+
<td className="block font-medium @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2 @lg/changes:align-top">
|
|
107
|
+
{humanizeField(normalizeChangeField(row.field))}
|
|
108
|
+
</td>
|
|
109
|
+
<td className="mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2">
|
|
110
|
+
<span className="mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden">
|
|
111
|
+
{beforeHeading}
|
|
112
|
+
</span>
|
|
113
|
+
{renderValue(row.from, noneLabel)}
|
|
114
|
+
</td>
|
|
115
|
+
<td className="mt-2 block @lg/changes:mt-0 @lg/changes:table-cell @lg/changes:px-4 @lg/changes:py-2">
|
|
116
|
+
<span className="mb-0.5 block text-xs font-medium uppercase tracking-wide text-muted-foreground @lg/changes:hidden">
|
|
117
|
+
{afterHeading}
|
|
118
|
+
</span>
|
|
119
|
+
{renderValue(row.to, noneLabel)}
|
|
120
|
+
</td>
|
|
121
|
+
</tr>
|
|
122
|
+
))}
|
|
123
|
+
</tbody>
|
|
124
|
+
</table>
|
|
125
|
+
</div>
|
|
116
126
|
</div>
|
|
117
127
|
) : (
|
|
118
128
|
<p className="mt-2 text-sm text-muted-foreground">
|