@burdenoff/microfe-coolandlovely 2026.820.5 → 2026.827.1
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/coolandlovely/components/ActivityTrail.d.ts +24 -0
- package/dist/coolandlovely/components/ActivityTrail.d.ts.map +1 -0
- package/dist/coolandlovely/components/ActivityTrail.js +70 -0
- package/dist/coolandlovely/components/ActivityTrail.js.map +1 -0
- package/dist/coolandlovely/components/index.d.ts +1 -0
- package/dist/coolandlovely/components/index.d.ts.map +1 -1
- package/dist/coolandlovely/components/index.js +1 -0
- package/dist/coolandlovely/hooks/index.d.ts +3 -0
- package/dist/coolandlovely/hooks/index.d.ts.map +1 -1
- package/dist/coolandlovely/hooks/index.js +2 -0
- package/dist/coolandlovely/hooks/useActivity.d.ts +39 -0
- package/dist/coolandlovely/hooks/useActivity.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useActivity.js +38 -0
- package/dist/coolandlovely/hooks/useActivity.js.map +1 -0
- package/dist/coolandlovely/hooks/useAssistantEntity.d.ts +24 -0
- package/dist/coolandlovely/hooks/useAssistantEntity.d.ts.map +1 -0
- package/dist/coolandlovely/hooks/useAssistantEntity.js +12 -0
- package/dist/coolandlovely/hooks/useAssistantEntity.js.map +1 -0
- package/dist/coolandlovely/pages/brands/BrandDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js +163 -143
- package/dist/coolandlovely/pages/brands/BrandDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js +114 -113
- package/dist/coolandlovely/pages/collaborations/CollaborationDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js +105 -104
- package/dist/coolandlovely/pages/collections/CollectionDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/discover/DiscoverPage.js +289 -151
- package/dist/coolandlovely/pages/discover/DiscoverPage.js.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js +110 -109
- package/dist/coolandlovely/pages/items/StyleItemDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js +18 -15
- package/dist/coolandlovely/pages/lookbooks/LookbookDetailPage.js.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.d.ts.map +1 -1
- package/dist/coolandlovely/pages/looks/LookDetailPage.js +129 -128
- package/dist/coolandlovely/pages/looks/LookDetailPage.js.map +1 -1
- package/dist/utils/pageContext.d.ts +23 -0
- package/dist/utils/pageContext.d.ts.map +1 -1
- package/dist/utils/pageContext.js +37 -25
- package/dist/utils/pageContext.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
interface ActivityTrailProps {
|
|
4
|
+
/** ActivityLog.resourceType written by the svc, e.g. "coolandlovely-brand". */
|
|
5
|
+
resourceType: string;
|
|
6
|
+
/** The record id (the panel stays idle until it is present). */
|
|
7
|
+
resourceId?: string;
|
|
8
|
+
/** Section heading (default "Audit trail"). */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Max entries to request (default 20). */
|
|
11
|
+
limit?: number;
|
|
12
|
+
className?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `coolandlovely.brand_transitioned` → "Brand transitioned".
|
|
16
|
+
*
|
|
17
|
+
* Only reshapes the snake_case event names the audit plugin emits; anything
|
|
18
|
+
* else (the generic `graphql_mutation` fallback, which carries the raw field
|
|
19
|
+
* name) is shown verbatim rather than mangled by a lowercase pass.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatActivityAction(action: string): string;
|
|
22
|
+
export declare const ActivityTrail: FC<ActivityTrailProps>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=ActivityTrail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActivityTrail.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/ActivityTrail.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAQhC,UAAU,kBAAkB;IAC1B,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CAkEhD,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { cn as e } from "../utils/cn.js";
|
|
2
|
+
import { formatDate as t, formatRelativeTime as n, titleCase as r } from "../utils/formatters.js";
|
|
3
|
+
import { useEntityActivity as i } from "../hooks/useActivity.js";
|
|
4
|
+
import { ActorName as a } from "./ActorName.js";
|
|
5
|
+
import { History as o, Loader2 as s, RotateCw as c } from "lucide-react";
|
|
6
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
|
+
import { GlassCard as d } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
//#region src/coolandlovely/components/ActivityTrail.tsx
|
|
9
|
+
function f(e) {
|
|
10
|
+
let t = e.includes(".") ? e.slice(e.lastIndexOf(".") + 1) : e;
|
|
11
|
+
if (!/^[a-z0-9_]+$/.test(t)) return e;
|
|
12
|
+
let n = r(t);
|
|
13
|
+
return n.charAt(0) + n.slice(1).toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
var p = ({ resourceType: r, resourceId: p, title: m = "Audit trail", limit: h = 20, className: g }) => {
|
|
16
|
+
let _ = i(r, p, h), v = _.data ?? [];
|
|
17
|
+
return /* @__PURE__ */ u(d, {
|
|
18
|
+
treatment: "plain",
|
|
19
|
+
className: e("p-5", g),
|
|
20
|
+
children: [/* @__PURE__ */ u("h3", {
|
|
21
|
+
className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ l(o, { className: "h-4 w-4" }),
|
|
24
|
+
" ",
|
|
25
|
+
m
|
|
26
|
+
]
|
|
27
|
+
}), _.isError ? /* @__PURE__ */ u("div", {
|
|
28
|
+
className: "space-y-2",
|
|
29
|
+
children: [/* @__PURE__ */ l("p", {
|
|
30
|
+
className: "text-sm text-text-secondary",
|
|
31
|
+
children: "Activity could not be loaded for this record."
|
|
32
|
+
}), /* @__PURE__ */ u("button", {
|
|
33
|
+
type: "button",
|
|
34
|
+
onClick: () => void _.refetch(),
|
|
35
|
+
className: "inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken",
|
|
36
|
+
children: [/* @__PURE__ */ l(c, { className: "h-3.5 w-3.5" }), " Retry"]
|
|
37
|
+
})]
|
|
38
|
+
}) : _.isFetched ? v.length === 0 ? /* @__PURE__ */ l("p", {
|
|
39
|
+
className: "text-sm text-text-secondary",
|
|
40
|
+
children: "No changes recorded yet. Edits, lifecycle transitions and archival are logged here as they happen."
|
|
41
|
+
}) : /* @__PURE__ */ l("ul", {
|
|
42
|
+
className: "divide-y divide-border-seam",
|
|
43
|
+
children: v.map((e) => /* @__PURE__ */ u("li", {
|
|
44
|
+
className: "flex items-start justify-between gap-3 py-2.5 first:pt-0",
|
|
45
|
+
children: [/* @__PURE__ */ u("div", {
|
|
46
|
+
className: "min-w-0",
|
|
47
|
+
children: [/* @__PURE__ */ l("p", {
|
|
48
|
+
className: "truncate text-sm font-medium text-text-primary",
|
|
49
|
+
children: f(e.action)
|
|
50
|
+
}), /* @__PURE__ */ l("p", {
|
|
51
|
+
className: "mt-0.5 truncate text-xs text-text-secondary",
|
|
52
|
+
children: /* @__PURE__ */ l(a, { id: e.userId })
|
|
53
|
+
})]
|
|
54
|
+
}), /* @__PURE__ */ l("time", {
|
|
55
|
+
dateTime: e.timestamp,
|
|
56
|
+
title: t(e.timestamp),
|
|
57
|
+
className: "shrink-0 whitespace-nowrap text-xs text-text-secondary",
|
|
58
|
+
children: n(e.timestamp)
|
|
59
|
+
})]
|
|
60
|
+
}, e.id))
|
|
61
|
+
}) : /* @__PURE__ */ u("p", {
|
|
62
|
+
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
63
|
+
children: [/* @__PURE__ */ l(s, { className: "h-4 w-4 animate-spin" }), " Loading activity…"]
|
|
64
|
+
})]
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
//#endregion
|
|
68
|
+
export { p as ActivityTrail };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=ActivityTrail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActivityTrail.js","names":[],"sources":["../../../src/coolandlovely/components/ActivityTrail.tsx"],"sourcesContent":["/**\n * ActivityTrail — resource-scoped audit trail for a CoolAndLovely record.\n * @module coolandlovely/components\n *\n * Reads the platform `ActivityLog` rows that the svc's mutation-audit plugin\n * already writes for every `coo*` mutation (see `hooks/useActivity.ts`). Who\n * changed what, when — resolved to a real display name via `ActorName`.\n *\n * No fabricated history: a record with no rows shows an empty state, and a\n * caller without the workspace `activity-log:read` permission sees the error\n * instead of a convincing-looking blank timeline.\n */\n\nimport type { FC } from 'react';\nimport { History, Loader2, RotateCw } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { ActorName } from './ActorName';\nimport { useEntityActivity } from '../hooks/useActivity';\nimport { formatDate, formatRelativeTime, titleCase } from '../utils/formatters';\nimport { cn } from '../utils/cn';\n\ninterface ActivityTrailProps {\n /** ActivityLog.resourceType written by the svc, e.g. \"coolandlovely-brand\". */\n resourceType: string;\n /** The record id (the panel stays idle until it is present). */\n resourceId?: string;\n /** Section heading (default \"Audit trail\"). */\n title?: string;\n /** Max entries to request (default 20). */\n limit?: number;\n className?: string;\n}\n\n/**\n * `coolandlovely.brand_transitioned` → \"Brand transitioned\".\n *\n * Only reshapes the snake_case event names the audit plugin emits; anything\n * else (the generic `graphql_mutation` fallback, which carries the raw field\n * name) is shown verbatim rather than mangled by a lowercase pass.\n */\nexport function formatActivityAction(action: string): string {\n const tail = action.includes('.') ? action.slice(action.lastIndexOf('.') + 1) : action;\n if (!/^[a-z0-9_]+$/.test(tail)) return action;\n const label = titleCase(tail);\n return label.charAt(0) + label.slice(1).toLowerCase();\n}\n\nexport const ActivityTrail: FC<ActivityTrailProps> = ({\n resourceType,\n resourceId,\n title = 'Audit trail',\n limit = 20,\n className,\n}) => {\n const query = useEntityActivity(resourceType, resourceId, limit);\n const entries = query.data ?? [];\n\n return (\n <GlassCard treatment=\"plain\" className={cn('p-5', className)}>\n <h3 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <History className=\"h-4 w-4\" /> {title}\n </h3>\n\n {query.isError ? (\n <div className=\"space-y-2\">\n <p className=\"text-sm text-text-secondary\">\n Activity could not be loaded for this record.\n </p>\n <button\n type=\"button\"\n onClick={() => void query.refetch()}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <RotateCw className=\"h-3.5 w-3.5\" /> Retry\n </button>\n </div>\n ) : !query.isFetched ? (\n // Deliberately NOT `isLoading`: a query held back (no record id, no\n // workspace) has never run, and \"no changes recorded\" would be a claim\n // about data we never asked for.\n <p className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> Loading activity…\n </p>\n ) : entries.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">\n No changes recorded yet. Edits, lifecycle transitions and archival are logged here as they\n happen.\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam\">\n {entries.map((entry) => (\n <li key={entry.id} className=\"flex items-start justify-between gap-3 py-2.5 first:pt-0\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n {formatActivityAction(entry.action)}\n </p>\n <p className=\"mt-0.5 truncate text-xs text-text-secondary\">\n <ActorName id={entry.userId} />\n </p>\n </div>\n <time\n dateTime={entry.timestamp}\n title={formatDate(entry.timestamp)}\n className=\"shrink-0 whitespace-nowrap text-xs text-text-secondary\"\n >\n {formatRelativeTime(entry.timestamp)}\n </time>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n );\n};\n"],"mappings":";;;;;;;;AAwCA,SAAgB,EAAqB,GAAwB;CAC3D,IAAM,IAAO,EAAO,SAAS,IAAI,GAAG,EAAO,MAAM,EAAO,YAAY,IAAI,GAAG,EAAE,GAAG;AAChF,KAAI,CAAC,eAAe,KAAK,EAAK,CAAE,QAAO;CACvC,IAAM,IAAQ,EAAU,EAAK;AAC7B,QAAO,EAAM,OAAO,EAAE,GAAG,EAAM,MAAM,EAAE,CAAC,aAAa;;AAGvD,IAAa,KAAyC,EACpD,iBACA,eACA,WAAQ,eACR,WAAQ,IACR,mBACI;CACJ,IAAM,IAAQ,EAAkB,GAAc,GAAY,EAAM,EAC1D,IAAU,EAAM,QAAQ,EAAE;AAEhC,QACE,kBAAC,GAAD;EAAW,WAAU;EAAQ,WAAW,EAAG,OAAO,EAAU;YAA5D,CACE,kBAAC,MAAD;GAAI,WAAU;aAAd;IACE,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA;;IAAE;IAC9B;MAEJ,EAAM,UACL,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAEvC,CAAA,EACJ,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,KAAK,EAAM,SAAS;IACnC,WAAU;cAHZ,CAKE,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA,EAAA,SAC7B;MACL;OACH,EAAM,YAOP,EAAQ,WAAW,IACrB,kBAAC,KAAD;GAAG,WAAU;aAA8B;GAGvC,CAAA,GAEJ,kBAAC,MAAD;GAAI,WAAU;aACX,EAAQ,KAAK,MACZ,kBAAC,MAAD;IAAmB,WAAU;cAA7B,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAqB,EAAM,OAAO;MACjC,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBACX,kBAAC,GAAD,EAAW,IAAI,EAAM,QAAU,CAAA;MAC7B,CAAA,CACA;QACN,kBAAC,QAAD;KACE,UAAU,EAAM;KAChB,OAAO,EAAW,EAAM,UAAU;KAClC,WAAU;eAET,EAAmB,EAAM,UAAU;KAC/B,CAAA,CACJ;MAhBI,EAAM,GAgBV,CACL;GACC,CAAA,GA7BL,kBAAC,KAAD;GAAG,WAAU;aAAb,CACE,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EAAA,qBAC1C;KA6BI"}
|
|
@@ -14,6 +14,7 @@ export { LoadingView, ErrorView } from './StateViews';
|
|
|
14
14
|
export { FieldShell, TextField, TextAreaField, SelectField, ToggleField } from './Field';
|
|
15
15
|
export { ActorName } from './ActorName';
|
|
16
16
|
export { Comments } from './Comments';
|
|
17
|
+
export { ActivityTrail } from './ActivityTrail';
|
|
17
18
|
export { FollowButton } from './FollowButton';
|
|
18
19
|
export { AddToLookbookButton } from './AddToLookbookButton';
|
|
19
20
|
export { LookCard } from './LookCard';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/components/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -8,4 +8,7 @@ export { uploadImageToFiles, useFileUrl, COO_FILE_FOLDERS } from './useFiles';
|
|
|
8
8
|
export type { UploadedImage, CooFileFolder } from './useFiles';
|
|
9
9
|
export { useEntityComments, useAddComment } from './useComments';
|
|
10
10
|
export type { EntityCommentView, EntityCommentsResult } from './useComments';
|
|
11
|
+
export { useEntityActivity } from './useActivity';
|
|
12
|
+
export type { CooActivityEntry } from './useActivity';
|
|
13
|
+
export { useAssistantEntityName } from './useAssistantEntity';
|
|
11
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,eAAe,EAEf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EAEpB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EAEnB,QAAQ,EACR,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EAEb,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,sBAAsB,EAEtB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EAErB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EAErB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EAEjB,cAAc,EACd,SAAS,EACT,WAAW,EACX,cAAc,EACd,cAAc,EAEd,mBAAmB,EACnB,cAAc,EAEd,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG/D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,SAAS,EACT,QAAQ,EACR,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,eAAe,EAEf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EAEpB,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EAEnB,QAAQ,EACR,iBAAiB,EACjB,OAAO,EACP,aAAa,EACb,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,aAAa,EAEb,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,sBAAsB,EAEtB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EAErB,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,qBAAqB,EAErB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EAEjB,cAAc,EACd,SAAS,EACT,WAAW,EACX,cAAc,EACd,cAAc,EAEd,mBAAmB,EACnB,cAAc,EAEd,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,YAAY,EACV,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,eAAe,GAChB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9E,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG/D,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAG7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit-trail hooks — activity via wspace-activity-svc (NO new table).
|
|
3
|
+
* @module coolandlovely/hooks
|
|
4
|
+
*
|
|
5
|
+
* CoolAndLovely does NOT own an audit table. Every `coo*` mutation is already
|
|
6
|
+
* recorded by the svc's mutation-audit plugin
|
|
7
|
+
* (`wspace-coolandlovely-svc/src/plugins/mutation-audit-plugin.ts`) through
|
|
8
|
+
* be-sdk `trackOperation`, which writes an `ActivityLog` row on
|
|
9
|
+
* wspace-activity-svc carrying:
|
|
10
|
+
*
|
|
11
|
+
* action — the plugin's `eventName`, e.g. `coolandlovely.brand_transitioned`
|
|
12
|
+
* description — `"<action> <resourceType>: <fieldName>"`
|
|
13
|
+
* resourceType — e.g. `coolandlovely-brand`
|
|
14
|
+
* resourceId — the affected record's id
|
|
15
|
+
* userId — the acting actor
|
|
16
|
+
*
|
|
17
|
+
* This hook is purely the read surface over those rows (`getActivities`,
|
|
18
|
+
* federated on the workspace supergraph). Nothing is synthesised: when the
|
|
19
|
+
* service has no rows for a record, callers render an empty state.
|
|
20
|
+
*/
|
|
21
|
+
/** A single audit entry as surfaced in the MFE (scalar-only projection). */
|
|
22
|
+
export interface CooActivityEntry {
|
|
23
|
+
id: string;
|
|
24
|
+
action: string;
|
|
25
|
+
description: string | null;
|
|
26
|
+
resourceType: string | null;
|
|
27
|
+
resourceId: string | null;
|
|
28
|
+
userId: string;
|
|
29
|
+
timestamp: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Audit entries for one record, newest first.
|
|
33
|
+
*
|
|
34
|
+
* `getActivities` is `@rbac(action: "read", resource: "activity-log",
|
|
35
|
+
* scopeType: "wspace")` — a member without that permission gets an error from
|
|
36
|
+
* the gateway, which callers surface honestly rather than hiding.
|
|
37
|
+
*/
|
|
38
|
+
export declare const useEntityActivity: (resourceType: string, resourceId: string | undefined, limit?: number) => import('@tanstack/react-query').UseQueryResult<NoInfer<CooActivityEntry[]>, Error>;
|
|
39
|
+
//# sourceMappingURL=useActivity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useActivity.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/useActivity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAqCD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,cAAc,MAAM,EACpB,YAAY,MAAM,GAAG,SAAS,EAC9B,cAAU,uFAiBX,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCoolAndLovely as e } from "../context/CoolAndLovelyContext.js";
|
|
2
|
+
import "../context/index.js";
|
|
3
|
+
import { useQuery as t } from "@tanstack/react-query";
|
|
4
|
+
import { graphqlFetch as n } from "@burdenoff/fe-libs/shared/graphql";
|
|
5
|
+
//#region src/coolandlovely/hooks/useActivity.ts
|
|
6
|
+
var r = "coolandlovely-activity", i = "\n query CooEntityActivity($filter: ActivityLogFilter) {\n getActivities(filter: $filter) {\n id\n action\n description\n resourceType\n resourceId\n userId\n timestamp\n }\n }\n", a = async (e, t, r) => {
|
|
7
|
+
let i = await n({
|
|
8
|
+
gateway: "workspace",
|
|
9
|
+
baseUrl: r,
|
|
10
|
+
query: e,
|
|
11
|
+
variables: t,
|
|
12
|
+
workspaceToken: !0
|
|
13
|
+
});
|
|
14
|
+
if (i.errors?.length) throw Error(i.errors[0]?.message ?? "Activity request failed");
|
|
15
|
+
if (!i.data) throw Error("Activity response did not include data");
|
|
16
|
+
return i.data;
|
|
17
|
+
}, o = (n, o, s = 20) => {
|
|
18
|
+
let { apiGatewayUrl: c, workspaceId: l } = e();
|
|
19
|
+
return t({
|
|
20
|
+
queryKey: [
|
|
21
|
+
r,
|
|
22
|
+
n,
|
|
23
|
+
o,
|
|
24
|
+
s
|
|
25
|
+
],
|
|
26
|
+
enabled: !!o && !!l,
|
|
27
|
+
queryFn: async () => [...(await a(i, { filter: {
|
|
28
|
+
workspaceId: l,
|
|
29
|
+
resourceType: n,
|
|
30
|
+
resourceId: o,
|
|
31
|
+
limit: s
|
|
32
|
+
} }, c)).getActivities].sort((e, t) => new Date(t.timestamp).getTime() - new Date(e.timestamp).getTime())
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
export { o as useEntityActivity };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=useActivity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useActivity.js","names":[],"sources":["../../../src/coolandlovely/hooks/useActivity.ts"],"sourcesContent":["/**\n * Audit-trail hooks — activity via wspace-activity-svc (NO new table).\n * @module coolandlovely/hooks\n *\n * CoolAndLovely does NOT own an audit table. Every `coo*` mutation is already\n * recorded by the svc's mutation-audit plugin\n * (`wspace-coolandlovely-svc/src/plugins/mutation-audit-plugin.ts`) through\n * be-sdk `trackOperation`, which writes an `ActivityLog` row on\n * wspace-activity-svc carrying:\n *\n * action — the plugin's `eventName`, e.g. `coolandlovely.brand_transitioned`\n * description — `\"<action> <resourceType>: <fieldName>\"`\n * resourceType — e.g. `coolandlovely-brand`\n * resourceId — the affected record's id\n * userId — the acting actor\n *\n * This hook is purely the read surface over those rows (`getActivities`,\n * federated on the workspace supergraph). Nothing is synthesised: when the\n * service has no rows for a record, callers render an empty state.\n */\n\nimport { useQuery } from '@tanstack/react-query';\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useCoolAndLovely } from '../context';\n\nconst QK = 'coolandlovely-activity';\n\n/** A single audit entry as surfaced in the MFE (scalar-only projection). */\nexport interface CooActivityEntry {\n id: string;\n action: string;\n description: string | null;\n resourceType: string | null;\n resourceId: string | null;\n userId: string;\n timestamp: string;\n}\n\nconst GET_ACTIVITIES = `\n query CooEntityActivity($filter: ActivityLogFilter) {\n getActivities(filter: $filter) {\n id\n action\n description\n resourceType\n resourceId\n userId\n timestamp\n }\n }\n`;\n\nconst activityFetch = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'Activity request failed');\n }\n if (!response.data) {\n throw new Error('Activity response did not include data');\n }\n return response.data;\n};\n\n/**\n * Audit entries for one record, newest first.\n *\n * `getActivities` is `@rbac(action: \"read\", resource: \"activity-log\",\n * scopeType: \"wspace\")` — a member without that permission gets an error from\n * the gateway, which callers surface honestly rather than hiding.\n */\nexport const useEntityActivity = (\n resourceType: string,\n resourceId: string | undefined,\n limit = 20\n) => {\n const { apiGatewayUrl, workspaceId } = useCoolAndLovely();\n return useQuery({\n queryKey: [QK, resourceType, resourceId, limit],\n enabled: Boolean(resourceId) && Boolean(workspaceId),\n queryFn: async (): Promise<CooActivityEntry[]> => {\n const data = await activityFetch<{ getActivities: CooActivityEntry[] }>(\n GET_ACTIVITIES,\n { filter: { workspaceId, resourceType, resourceId, limit } },\n apiGatewayUrl\n );\n return [...data.getActivities].sort(\n (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()\n );\n },\n });\n};\n"],"mappings":";;;;;AA0BA,IAAM,IAAK,0BAaL,IAAiB,iOAcjB,IAAgB,OACpB,GACA,GACA,MACmB;CACnB,IAAM,IAAW,MAAM,EAAoB;EACzC,SAAS;EACT;EACA;EACA;EACA,gBAAgB;EACjB,CAAC;AACF,KAAI,EAAS,QAAQ,OACnB,OAAU,MAAM,EAAS,OAAO,IAAI,WAAW,0BAA0B;AAE3E,KAAI,CAAC,EAAS,KACZ,OAAU,MAAM,yCAAyC;AAE3D,QAAO,EAAS;GAUL,KACX,GACA,GACA,IAAQ,OACL;CACH,IAAM,EAAE,kBAAe,mBAAgB,GAAkB;AACzD,QAAO,EAAS;EACd,UAAU;GAAC;GAAI;GAAc;GAAY;GAAM;EAC/C,SAAS,EAAQ,KAAe,EAAQ;EACxC,SAAS,YAMA,CAAC,IALK,MAAM,EACjB,GACA,EAAE,QAAQ;GAAE;GAAa;GAAc;GAAY;GAAO,EAAE,EAC5D,EACD,EACe,cAAc,CAAC,MAC5B,GAAG,MAAM,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,GAAG,IAAI,KAAK,EAAE,UAAU,CAAC,SAAS,CAC5E;EAEJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assistant screen-context hook.
|
|
3
|
+
* @module coolandlovely/hooks
|
|
4
|
+
*
|
|
5
|
+
* The floating assistant already receives `entityType` / `entityId`, both
|
|
6
|
+
* resolved from the URL. Neither tells the model WHAT the shopper is looking
|
|
7
|
+
* at, so "publish this storefront" or "what collections is this in" forces the
|
|
8
|
+
* assistant to echo a UUID back at a human.
|
|
9
|
+
*
|
|
10
|
+
* `entityName` is one of the agent's allowed context keys
|
|
11
|
+
* (`~/products/wspace/sandbox/ai-assistant/src/context-loader.ts`), but nothing
|
|
12
|
+
* in this product ever sent it. Detail pages call this hook with the name from
|
|
13
|
+
* their own loaded record — no extra request, no invented label — and it is
|
|
14
|
+
* withdrawn again on unmount.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Publish the current entity's display name to the assistant page context.
|
|
18
|
+
*
|
|
19
|
+
* Safe to call before the record has loaded: a missing id or name simply
|
|
20
|
+
* publishes nothing, so the assistant falls back to the id-only context it
|
|
21
|
+
* gets today rather than receiving a placeholder.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useAssistantEntityName(entityId: string | undefined, entityName: string | null | undefined): void;
|
|
24
|
+
//# sourceMappingURL=useAssistantEntity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAssistantEntity.d.ts","sourceRoot":"","sources":["../../../src/coolandlovely/hooks/useAssistantEntity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,IAAI,CAMN"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { clearActiveEntityName as e, setActiveEntityName as t } from "../../utils/pageContext.js";
|
|
2
|
+
import { useEffect as n } from "react";
|
|
3
|
+
//#region src/coolandlovely/hooks/useAssistantEntity.ts
|
|
4
|
+
function r(r, i) {
|
|
5
|
+
n(() => {
|
|
6
|
+
if (!(!r || !i)) return t(r, i), () => e(r);
|
|
7
|
+
}, [r, i]);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
export { r as useAssistantEntityName };
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=useAssistantEntity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAssistantEntity.js","names":[],"sources":["../../../src/coolandlovely/hooks/useAssistantEntity.ts"],"sourcesContent":["/**\n * Assistant screen-context hook.\n * @module coolandlovely/hooks\n *\n * The floating assistant already receives `entityType` / `entityId`, both\n * resolved from the URL. Neither tells the model WHAT the shopper is looking\n * at, so \"publish this storefront\" or \"what collections is this in\" forces the\n * assistant to echo a UUID back at a human.\n *\n * `entityName` is one of the agent's allowed context keys\n * (`~/products/wspace/sandbox/ai-assistant/src/context-loader.ts`), but nothing\n * in this product ever sent it. Detail pages call this hook with the name from\n * their own loaded record — no extra request, no invented label — and it is\n * withdrawn again on unmount.\n */\n\nimport { useEffect } from 'react';\n\nimport { clearActiveEntityName, setActiveEntityName } from '../../utils/pageContext';\n\n/**\n * Publish the current entity's display name to the assistant page context.\n *\n * Safe to call before the record has loaded: a missing id or name simply\n * publishes nothing, so the assistant falls back to the id-only context it\n * gets today rather than receiving a placeholder.\n */\nexport function useAssistantEntityName(\n entityId: string | undefined,\n entityName: string | null | undefined\n): void {\n useEffect(() => {\n if (!entityId || !entityName) return;\n setActiveEntityName(entityId, entityName);\n return () => clearActiveEntityName(entityId);\n }, [entityId, entityName]);\n}\n"],"mappings":";;;AA2BA,SAAgB,EACd,GACA,GACM;AACN,SAAgB;AACV,SAAC,KAAY,CAAC,GAElB,QADA,EAAoB,GAAU,EAAW,QAC5B,EAAsB,EAAS;IAC3C,CAAC,GAAU,EAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrandDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/brands/BrandDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"BrandDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/coolandlovely/pages/brands/BrandDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA+CH,wBAAgB,eAAe,gCAkT9B"}
|