@ai-matrx/associations 0.6.1 → 0.7.0
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/CHANGELOG.md +34 -0
- package/README.md +13 -7
- package/dist/{CommentThread-E0zSQBbc.d.cts → CommentThread-HW4hLdsd.d.cts} +13 -3
- package/dist/{CommentThread-E0zSQBbc.d.ts → CommentThread-HW4hLdsd.d.ts} +13 -3
- package/dist/core/index.cjs +2 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -3
- package/dist/index.d.ts +19 -3
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +130 -15
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +130 -15
- package/dist/react/index.js.map +1 -1
- package/dist/react/lazy/index.d.cts +1 -1
- package/dist/react/lazy/index.d.ts +1 -1
- package/package.json +2 -2
package/dist/react/index.cjs
CHANGED
|
@@ -429,6 +429,7 @@ var ENTITY_TYPE_TOKENS = [
|
|
|
429
429
|
"commerce_asset_reshoot_request",
|
|
430
430
|
"commerce_asset_review",
|
|
431
431
|
"commerce_asset_unknown",
|
|
432
|
+
"commerce_certified_printer",
|
|
432
433
|
"commerce_cloud_sync_connection",
|
|
433
434
|
"commerce_ebay_business_policy",
|
|
434
435
|
"commerce_ebay_category",
|
|
@@ -1108,6 +1109,12 @@ var useEntityRelationships = useAssociations;
|
|
|
1108
1109
|
|
|
1109
1110
|
// src/react/hooks/useContainerLinks.ts
|
|
1110
1111
|
var import_react3 = require("react");
|
|
1112
|
+
function metadataRecord(metadata) {
|
|
1113
|
+
if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
1114
|
+
return metadata == null ? {} : null;
|
|
1115
|
+
}
|
|
1116
|
+
return Object.fromEntries(Object.entries(metadata));
|
|
1117
|
+
}
|
|
1111
1118
|
function useContainerLinks(args) {
|
|
1112
1119
|
const { containerType, containerId, orgId } = args;
|
|
1113
1120
|
const store = useAssociationsStore();
|
|
@@ -1229,6 +1236,31 @@ function useContainerLinks(args) {
|
|
|
1229
1236
|
}
|
|
1230
1237
|
return result;
|
|
1231
1238
|
};
|
|
1239
|
+
const setPinned = async (token, resourceId, pinned, role) => {
|
|
1240
|
+
if (!containerId) return { ok: false, error: "Missing container id" };
|
|
1241
|
+
const exactRole = role ?? null;
|
|
1242
|
+
const link = incoming.find(
|
|
1243
|
+
(candidate) => candidate.token === token && candidate.resourceId === resourceId && candidate.role === exactRole
|
|
1244
|
+
);
|
|
1245
|
+
if (!link) return { ok: false, error: "Association edge not found" };
|
|
1246
|
+
const currentMetadata = metadataRecord(link.metadata);
|
|
1247
|
+
if (!currentMetadata) {
|
|
1248
|
+
return {
|
|
1249
|
+
ok: false,
|
|
1250
|
+
error: "Association metadata is not an object and cannot be updated safely"
|
|
1251
|
+
};
|
|
1252
|
+
}
|
|
1253
|
+
return store.add({
|
|
1254
|
+
sourceType: token,
|
|
1255
|
+
sourceId: resourceId,
|
|
1256
|
+
targetType: containerType,
|
|
1257
|
+
targetId: containerId,
|
|
1258
|
+
...orgId != null ? { orgId } : {},
|
|
1259
|
+
...link.label != null ? { label: link.label } : {},
|
|
1260
|
+
...role !== void 0 ? { role } : {},
|
|
1261
|
+
metadata: { ...currentMetadata, pinned }
|
|
1262
|
+
});
|
|
1263
|
+
};
|
|
1232
1264
|
const reload = async () => {
|
|
1233
1265
|
await Promise.all([
|
|
1234
1266
|
reloadGeneric(),
|
|
@@ -1246,7 +1278,8 @@ function useContainerLinks(args) {
|
|
|
1246
1278
|
attachedIdsFor,
|
|
1247
1279
|
linksFor,
|
|
1248
1280
|
attach,
|
|
1249
|
-
detach
|
|
1281
|
+
detach,
|
|
1282
|
+
setPinned
|
|
1250
1283
|
};
|
|
1251
1284
|
}
|
|
1252
1285
|
|
|
@@ -2627,6 +2660,9 @@ function UniversalAssociationPicker(props) {
|
|
|
2627
2660
|
var import_react15 = require("react");
|
|
2628
2661
|
var import_design_system5 = require("@ai-matrx/design-system");
|
|
2629
2662
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
2663
|
+
function metadataIsPinned(metadata) {
|
|
2664
|
+
return metadata !== null && typeof metadata === "object" && !Array.isArray(metadata) && Reflect.get(metadata, "pinned") === true;
|
|
2665
|
+
}
|
|
2630
2666
|
function AttachedItemsSheet(props) {
|
|
2631
2667
|
const store = useAssociationsStore();
|
|
2632
2668
|
const info = store.registry.getEntityInfo(props.token);
|
|
@@ -2662,7 +2698,8 @@ function AttachedItemsSheet(props) {
|
|
|
2662
2698
|
enabled: props.open,
|
|
2663
2699
|
links: props.links,
|
|
2664
2700
|
...props.onAdd ? { onAdd: props.onAdd } : {},
|
|
2665
|
-
onDetach: props.onDetach
|
|
2701
|
+
onDetach: props.onDetach,
|
|
2702
|
+
...props.onSetPinned ? { onSetPinned: props.onSetPinned } : {}
|
|
2666
2703
|
}
|
|
2667
2704
|
)
|
|
2668
2705
|
}
|
|
@@ -2673,7 +2710,8 @@ function AttachedItemsBody({
|
|
|
2673
2710
|
enabled,
|
|
2674
2711
|
links,
|
|
2675
2712
|
onAdd,
|
|
2676
|
-
onDetach
|
|
2713
|
+
onDetach,
|
|
2714
|
+
onSetPinned
|
|
2677
2715
|
}) {
|
|
2678
2716
|
const store = useAssociationsStore();
|
|
2679
2717
|
const notifier = useNotifier();
|
|
@@ -2715,11 +2753,12 @@ function AttachedItemsBody({
|
|
|
2715
2753
|
cancelled = true;
|
|
2716
2754
|
};
|
|
2717
2755
|
}, [token, idKey, enabled, store]);
|
|
2718
|
-
const detach = async (
|
|
2756
|
+
const detach = async (link) => {
|
|
2757
|
+
const resourceId = link.resourceId;
|
|
2719
2758
|
if (busyId) return;
|
|
2720
2759
|
setBusyId(resourceId);
|
|
2721
2760
|
try {
|
|
2722
|
-
const res = await onDetach(resourceId);
|
|
2761
|
+
const res = await onDetach(resourceId, link.role);
|
|
2723
2762
|
if (!res.ok) {
|
|
2724
2763
|
notifier.error(`Couldn't detach${res.error ? `: ${res.error}` : ""}`);
|
|
2725
2764
|
}
|
|
@@ -2727,6 +2766,20 @@ function AttachedItemsBody({
|
|
|
2727
2766
|
setBusyId(null);
|
|
2728
2767
|
}
|
|
2729
2768
|
};
|
|
2769
|
+
const setPinned = async (link, pinned) => {
|
|
2770
|
+
if (!onSetPinned || busyId) return;
|
|
2771
|
+
setBusyId(link.resourceId);
|
|
2772
|
+
try {
|
|
2773
|
+
const res = await onSetPinned(link.resourceId, pinned, link.role);
|
|
2774
|
+
if (!res.ok) {
|
|
2775
|
+
notifier.error(
|
|
2776
|
+
`Couldn't ${pinned ? "pin" : "unpin"}${res.error ? `: ${res.error}` : ""}`
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
} finally {
|
|
2780
|
+
setBusyId(null);
|
|
2781
|
+
}
|
|
2782
|
+
};
|
|
2730
2783
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
|
|
2731
2784
|
titleError ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "mb-2 rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12px] text-destructive", children: [
|
|
2732
2785
|
"Showing names recorded at attach time \u2014 they may be out of date.",
|
|
@@ -2741,6 +2794,7 @@ function AttachedItemsBody({
|
|
|
2741
2794
|
const missing = !titles.has(link.resourceId);
|
|
2742
2795
|
const name = resolved ?? link.label ?? (missing ? null : "Untitled");
|
|
2743
2796
|
const busy = busyId === link.resourceId;
|
|
2797
|
+
const pinned = metadataIsPinned(link.metadata);
|
|
2744
2798
|
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
2745
2799
|
"li",
|
|
2746
2800
|
{
|
|
@@ -2760,12 +2814,35 @@ function AttachedItemsBody({
|
|
|
2760
2814
|
className: "text-foreground"
|
|
2761
2815
|
}
|
|
2762
2816
|
) }),
|
|
2817
|
+
onSetPinned ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2818
|
+
"button",
|
|
2819
|
+
{
|
|
2820
|
+
type: "button",
|
|
2821
|
+
disabled: busy,
|
|
2822
|
+
onClick: () => void setPinned(link, !pinned),
|
|
2823
|
+
title: pinned ? "Unpin (stops staying in agent context)" : "Pin \u2014 always in agent context",
|
|
2824
|
+
"aria-label": pinned ? "Unpin" : "Pin",
|
|
2825
|
+
className: (0, import_design_system5.cn)(
|
|
2826
|
+
"flex h-6 w-6 shrink-0 items-center justify-center rounded-md transition-colors hover:bg-accent hover:text-foreground disabled:opacity-50",
|
|
2827
|
+
pinned ? "text-primary" : "text-muted-foreground"
|
|
2828
|
+
),
|
|
2829
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2830
|
+
PinIcon,
|
|
2831
|
+
{
|
|
2832
|
+
className: (0, import_design_system5.cn)(
|
|
2833
|
+
"h-3.5 w-3.5",
|
|
2834
|
+
pinned && "fill-primary/20"
|
|
2835
|
+
)
|
|
2836
|
+
}
|
|
2837
|
+
)
|
|
2838
|
+
}
|
|
2839
|
+
) : null,
|
|
2763
2840
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
2764
2841
|
"button",
|
|
2765
2842
|
{
|
|
2766
2843
|
type: "button",
|
|
2767
2844
|
disabled: busy,
|
|
2768
|
-
onClick: () => void detach(link
|
|
2845
|
+
onClick: () => void detach(link),
|
|
2769
2846
|
title: "Detach",
|
|
2770
2847
|
className: (0, import_design_system5.cn)(
|
|
2771
2848
|
"flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors",
|
|
@@ -2861,7 +2938,15 @@ function AssociationCard({
|
|
|
2861
2938
|
const role = getContentRoleMeta(info.contentRole);
|
|
2862
2939
|
const Icon = info.Icon ?? DefaultEntityIcon;
|
|
2863
2940
|
const [listOpen, setListOpen] = (0, import_react16.useState)(false);
|
|
2864
|
-
const {
|
|
2941
|
+
const {
|
|
2942
|
+
status,
|
|
2943
|
+
countFor,
|
|
2944
|
+
attachedIdsFor,
|
|
2945
|
+
linksFor,
|
|
2946
|
+
attach,
|
|
2947
|
+
detach,
|
|
2948
|
+
setPinned
|
|
2949
|
+
} = useContainerLinks({
|
|
2865
2950
|
containerType: container?.type ?? "organization",
|
|
2866
2951
|
containerId: container?.id ?? null,
|
|
2867
2952
|
orgId: container?.orgId ?? null
|
|
@@ -2958,7 +3043,8 @@ function AssociationCard({
|
|
|
2958
3043
|
setOpen(true);
|
|
2959
3044
|
}
|
|
2960
3045
|
} : {},
|
|
2961
|
-
onDetach: (resourceId) => detach(token, resourceId)
|
|
3046
|
+
onDetach: (resourceId, role2) => detach(token, resourceId, role2 ?? void 0),
|
|
3047
|
+
onSetPinned: (resourceId, pinned, role2) => setPinned(token, resourceId, pinned, role2 ?? void 0)
|
|
2962
3048
|
}
|
|
2963
3049
|
),
|
|
2964
3050
|
canAttach && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
@@ -3017,6 +3103,9 @@ function AssociationCardGrid({
|
|
|
3017
3103
|
var import_react17 = require("react");
|
|
3018
3104
|
var import_design_system8 = require("@ai-matrx/design-system");
|
|
3019
3105
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
3106
|
+
function metadataIsPinned2(metadata) {
|
|
3107
|
+
return metadata !== null && typeof metadata === "object" && !Array.isArray(metadata) && Reflect.get(metadata, "pinned") === true;
|
|
3108
|
+
}
|
|
3020
3109
|
function useContainerLinksAdapter(container, tokens) {
|
|
3021
3110
|
const store = useAssociationsStore();
|
|
3022
3111
|
const links = useContainerLinks({
|
|
@@ -3031,6 +3120,7 @@ function useContainerLinksAdapter(container, tokens) {
|
|
|
3031
3120
|
resourceId: l.resourceId,
|
|
3032
3121
|
label: l.label,
|
|
3033
3122
|
role: l.role,
|
|
3123
|
+
pinned: metadataIsPinned2(l.metadata),
|
|
3034
3124
|
removable: true
|
|
3035
3125
|
}))
|
|
3036
3126
|
) : [];
|
|
@@ -3040,11 +3130,13 @@ function useContainerLinksAdapter(container, tokens) {
|
|
|
3040
3130
|
reload: links.reload,
|
|
3041
3131
|
rows,
|
|
3042
3132
|
attach: async (token, id, title) => links.attach(token, id, title),
|
|
3043
|
-
detach: async (token, id, role) => links.detach(token, id, role)
|
|
3133
|
+
detach: async (token, id, role) => links.detach(token, id, role),
|
|
3134
|
+
setPinned: async (token, id, pinned, role) => links.setPinned(token, id, pinned, role)
|
|
3044
3135
|
};
|
|
3045
3136
|
}
|
|
3046
3137
|
function AssociationList(props) {
|
|
3047
3138
|
const store = useAssociationsStore();
|
|
3139
|
+
const notifier = useNotifier();
|
|
3048
3140
|
const ctxEntity = usePrimaryEntity();
|
|
3049
3141
|
const container = props.container ?? ctxEntity ?? null;
|
|
3050
3142
|
const defaultAdapter = useContainerLinksAdapter(
|
|
@@ -3057,6 +3149,7 @@ function AssociationList(props) {
|
|
|
3057
3149
|
const [pickerToken, setPickerToken] = (0, import_react17.useState)(null);
|
|
3058
3150
|
const [showUniversal, setShowUniversal] = (0, import_react17.useState)(false);
|
|
3059
3151
|
const [removingKeys, setRemovingKeys] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
|
|
3152
|
+
const [pinningKeys, setPinningKeys] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
|
|
3060
3153
|
const rows = tokenFilter ? adapter.rows.filter((r) => tokenFilter.includes(r.token)) : adapter.rows;
|
|
3061
3154
|
const visibleRows = rows.filter((r) => !removingKeys.has(r.key));
|
|
3062
3155
|
const { titleFor } = useEntityTitles(
|
|
@@ -3080,6 +3173,31 @@ function AssociationList(props) {
|
|
|
3080
3173
|
});
|
|
3081
3174
|
return res;
|
|
3082
3175
|
};
|
|
3176
|
+
const handlePin = async (row, pinned) => {
|
|
3177
|
+
if (!adapter.setPinned) return;
|
|
3178
|
+
const info = store.registry.tryGetEntityInfo(row.token);
|
|
3179
|
+
if (!info) return;
|
|
3180
|
+
setPinningKeys((prev) => new Set(prev).add(row.key));
|
|
3181
|
+
try {
|
|
3182
|
+
const res = await adapter.setPinned(
|
|
3183
|
+
info.token,
|
|
3184
|
+
row.resourceId,
|
|
3185
|
+
pinned,
|
|
3186
|
+
row.role ?? void 0
|
|
3187
|
+
);
|
|
3188
|
+
if (!res.ok) {
|
|
3189
|
+
notifier.error(
|
|
3190
|
+
`Couldn't ${pinned ? "pin" : "unpin"} resource${res.error ? `: ${res.error}` : ""}`
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
} finally {
|
|
3194
|
+
setPinningKeys((prev) => {
|
|
3195
|
+
const next = new Set(prev);
|
|
3196
|
+
next.delete(row.key);
|
|
3197
|
+
return next;
|
|
3198
|
+
});
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3083
3201
|
const openRow = (row) => {
|
|
3084
3202
|
if (props.openEntity) {
|
|
3085
3203
|
props.openEntity(row.token, row.resourceId);
|
|
@@ -3270,18 +3388,15 @@ function AssociationList(props) {
|
|
|
3270
3388
|
"button",
|
|
3271
3389
|
{
|
|
3272
3390
|
type: "button",
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
row.resourceId,
|
|
3276
|
-
!(row.pinned ?? false)
|
|
3277
|
-
),
|
|
3391
|
+
disabled: pinningKeys.has(row.key),
|
|
3392
|
+
onClick: () => void handlePin(row, !(row.pinned ?? false)),
|
|
3278
3393
|
title: row.pinned ? "Unpin (stops staying in agent context)" : "Pin \u2014 always in agent context",
|
|
3279
3394
|
"aria-label": row.pinned ? "Unpin" : "Pin",
|
|
3280
3395
|
className: (0, import_design_system8.cn)(
|
|
3281
3396
|
"shrink-0 rounded p-0.5 transition-colors hover:!text-foreground",
|
|
3282
3397
|
row.pinned ? "text-primary" : "text-muted-foreground/0 group-hover:text-muted-foreground"
|
|
3283
3398
|
),
|
|
3284
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3399
|
+
children: pinningKeys.has(row.key) ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SpinnerIcon, { className: "h-3 w-3 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
3285
3400
|
PinIcon,
|
|
3286
3401
|
{
|
|
3287
3402
|
className: (0, import_design_system8.cn)(
|