@manta-eu/react 0.1.0 → 0.1.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.
Files changed (109) hide show
  1. package/README.md +101 -35
  2. package/dist/components/channel-icon/index.d.ts +1 -2
  3. package/dist/components/channel-icon/index.d.ts.map +1 -1
  4. package/dist/components/channel-icon/index.js +0 -4
  5. package/dist/components/plan-row/index.d.ts +2 -1
  6. package/dist/components/plan-row/index.d.ts.map +1 -1
  7. package/dist/components/plan-row/index.js +2 -14
  8. package/dist/globals.css +146 -90
  9. package/dist/graph/nodes/AdMockupCard.js +1 -1
  10. package/dist/graph/nodes/CreativeMediaCard.js +1 -1
  11. package/dist/graph/nodes/EntityCardShell.js +1 -1
  12. package/dist/hooks/use-conversation-starters.d.ts +1 -1
  13. package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
  14. package/dist/routes/memories/components/ChangeScopeDialog.d.ts +12 -0
  15. package/dist/routes/memories/components/ChangeScopeDialog.d.ts.map +1 -0
  16. package/dist/routes/memories/components/ChangeScopeDialog.js +89 -0
  17. package/dist/routes/memories/components/ConflictMemoryCard.d.ts +13 -0
  18. package/dist/routes/memories/components/ConflictMemoryCard.d.ts.map +1 -0
  19. package/dist/routes/memories/components/ConflictMemoryCard.js +43 -0
  20. package/dist/routes/memories/components/ConflictTimeoutFooter.d.ts +7 -0
  21. package/dist/routes/memories/components/ConflictTimeoutFooter.d.ts.map +1 -0
  22. package/dist/routes/memories/components/ConflictTimeoutFooter.js +6 -0
  23. package/dist/routes/memories/components/ConsolidationReviewDialog.d.ts +61 -0
  24. package/dist/routes/memories/components/ConsolidationReviewDialog.d.ts.map +1 -0
  25. package/dist/routes/memories/components/ConsolidationReviewDialog.js +121 -0
  26. package/dist/routes/memories/components/EmptyStates.d.ts +18 -0
  27. package/dist/routes/memories/components/EmptyStates.d.ts.map +1 -0
  28. package/dist/routes/memories/components/EmptyStates.js +22 -0
  29. package/dist/routes/memories/components/ImportanceSlider.d.ts +11 -0
  30. package/dist/routes/memories/components/ImportanceSlider.d.ts.map +1 -0
  31. package/dist/routes/memories/components/ImportanceSlider.js +31 -0
  32. package/dist/routes/memories/components/LiveContextTab.d.ts +6 -0
  33. package/dist/routes/memories/components/LiveContextTab.d.ts.map +1 -0
  34. package/dist/routes/memories/components/LiveContextTab.js +37 -0
  35. package/dist/routes/memories/components/LoadingSkeleton.d.ts +2 -0
  36. package/dist/routes/memories/components/LoadingSkeleton.d.ts.map +1 -0
  37. package/dist/routes/memories/components/LoadingSkeleton.js +7 -0
  38. package/dist/routes/memories/components/MemoriesFilters.d.ts +31 -0
  39. package/dist/routes/memories/components/MemoriesFilters.d.ts.map +1 -0
  40. package/dist/routes/memories/components/MemoriesFilters.js +88 -0
  41. package/dist/routes/memories/components/MemoriesPanel.d.ts +6 -0
  42. package/dist/routes/memories/components/MemoriesPanel.d.ts.map +1 -0
  43. package/dist/routes/memories/components/MemoriesPanel.js +99 -0
  44. package/dist/routes/memories/components/MemoriesTabPanel.d.ts +30 -0
  45. package/dist/routes/memories/components/MemoriesTabPanel.d.ts.map +1 -0
  46. package/dist/routes/memories/components/MemoriesTabPanel.js +11 -0
  47. package/dist/routes/memories/components/MemoryActions.d.ts +12 -0
  48. package/dist/routes/memories/components/MemoryActions.d.ts.map +1 -0
  49. package/dist/routes/memories/components/MemoryActions.js +24 -0
  50. package/dist/routes/memories/components/MemoryFields.d.ts +32 -0
  51. package/dist/routes/memories/components/MemoryFields.d.ts.map +1 -0
  52. package/dist/routes/memories/components/MemoryFields.js +30 -0
  53. package/dist/routes/memories/components/MemoryFormDialog.d.ts +15 -0
  54. package/dist/routes/memories/components/MemoryFormDialog.d.ts.map +1 -0
  55. package/dist/routes/memories/components/MemoryFormDialog.js +299 -0
  56. package/dist/routes/memories/components/MemoryOnboardingWizard.d.ts +9 -0
  57. package/dist/routes/memories/components/MemoryOnboardingWizard.d.ts.map +1 -0
  58. package/dist/routes/memories/components/MemoryOnboardingWizard.js +99 -0
  59. package/dist/routes/memories/components/RestoreBlockedDialog.d.ts +8 -0
  60. package/dist/routes/memories/components/RestoreBlockedDialog.d.ts.map +1 -0
  61. package/dist/routes/memories/components/RestoreBlockedDialog.js +7 -0
  62. package/dist/routes/memories/components/SchemasTab.d.ts +6 -0
  63. package/dist/routes/memories/components/SchemasTab.d.ts.map +1 -0
  64. package/dist/routes/memories/components/SchemasTab.js +35 -0
  65. package/dist/routes/memories/components/SupersessionConflictDialog.d.ts +18 -0
  66. package/dist/routes/memories/components/SupersessionConflictDialog.d.ts.map +1 -0
  67. package/dist/routes/memories/components/SupersessionConflictDialog.js +78 -0
  68. package/dist/routes/memories/components/TeamPicker.d.ts +8 -0
  69. package/dist/routes/memories/components/TeamPicker.d.ts.map +1 -0
  70. package/dist/routes/memories/components/TeamPicker.js +25 -0
  71. package/dist/routes/memories/components/badges.d.ts +50 -0
  72. package/dist/routes/memories/components/badges.d.ts.map +1 -0
  73. package/dist/routes/memories/components/badges.js +106 -0
  74. package/dist/routes/memories/expiry-utils.d.ts +23 -0
  75. package/dist/routes/memories/expiry-utils.d.ts.map +1 -0
  76. package/dist/routes/memories/expiry-utils.js +97 -0
  77. package/dist/routes/memories/hooks/useConflictCheck.d.ts +18 -0
  78. package/dist/routes/memories/hooks/useConflictCheck.d.ts.map +1 -0
  79. package/dist/routes/memories/hooks/useConflictCheck.js +35 -0
  80. package/dist/routes/memories/hooks/useDuplicateDetection.d.ts +11 -0
  81. package/dist/routes/memories/hooks/useDuplicateDetection.d.ts.map +1 -0
  82. package/dist/routes/memories/hooks/useDuplicateDetection.js +73 -0
  83. package/dist/routes/memories/hooks/useLiveContext.d.ts +23 -0
  84. package/dist/routes/memories/hooks/useLiveContext.d.ts.map +1 -0
  85. package/dist/routes/memories/hooks/useLiveContext.js +102 -0
  86. package/dist/routes/memories/hooks/useMemoryColumns.d.ts +33 -0
  87. package/dist/routes/memories/hooks/useMemoryColumns.d.ts.map +1 -0
  88. package/dist/routes/memories/hooks/useMemoryColumns.js +188 -0
  89. package/dist/routes/memories/hooks/useMemoryTable.d.ts +33 -0
  90. package/dist/routes/memories/hooks/useMemoryTable.d.ts.map +1 -0
  91. package/dist/routes/memories/hooks/useMemoryTable.js +121 -0
  92. package/dist/routes/memories/index.d.ts +11 -0
  93. package/dist/routes/memories/index.d.ts.map +1 -0
  94. package/dist/routes/memories/index.js +472 -0
  95. package/dist/routes/memories/memory-form-validation.d.ts +8 -0
  96. package/dist/routes/memories/memory-form-validation.d.ts.map +1 -0
  97. package/dist/routes/memories/memory-form-validation.js +33 -0
  98. package/dist/routes/memories/memory-mutation-input.d.ts +6 -0
  99. package/dist/routes/memories/memory-mutation-input.d.ts.map +1 -0
  100. package/dist/routes/memories/memory-mutation-input.js +41 -0
  101. package/dist/routes/plans/components/actionPlansTableConfig.d.ts +3 -3
  102. package/package.json +12 -7
  103. package/src/globals.css +13 -18
  104. package/src/themes/manta-dark.css +0 -4
  105. package/src/themes/standard.css +11 -11
  106. package/dist/components/channel-icon/marketer-icon.d.ts +0 -4
  107. package/dist/components/channel-icon/marketer-icon.d.ts.map +0 -1
  108. package/dist/components/channel-icon/marketer-icon.js +0 -6
  109. package/src/themes/marketer-dark.css +0 -70
@@ -0,0 +1,18 @@
1
+ import { GQLMemoryScope, type GQLConflictingMemory } from "@manta-eu/client";
2
+ export type ConflictCheckInput = {
3
+ label: string;
4
+ description: string;
5
+ scope: GQLMemoryScope;
6
+ teams?: string[];
7
+ excludeIri?: string;
8
+ };
9
+ export type ConflictCheckResult = {
10
+ conflicts: GQLConflictingMemory[];
11
+ timedOut: boolean;
12
+ };
13
+ export type UseConflictCheckResult = {
14
+ check: (input: ConflictCheckInput) => Promise<ConflictCheckResult>;
15
+ isChecking: boolean;
16
+ };
17
+ export declare function useConflictCheck(): UseConflictCheckResult;
18
+ //# sourceMappingURL=useConflictCheck.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConflictCheck.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/hooks/useConflictCheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACd,KAAK,oBAAoB,EAG1B,MAAM,kBAAkB,CAAC;AAM1B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnE,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,gBAAgB,IAAI,sBAAsB,CAmCzD"}
@@ -0,0 +1,35 @@
1
+ import { DetectMemoryConflictsDocument, GQLMemoryScope, } from "@manta-eu/client";
2
+ import { useCallback, useState } from "react";
3
+ import { useMantaClient } from "#providers/index";
4
+ const conflictCheckTimeoutMs = 15_000;
5
+ export function useConflictCheck() {
6
+ const { mantaClient } = useMantaClient();
7
+ const [isChecking, setIsChecking] = useState(false);
8
+ const check = useCallback(async (input) => {
9
+ setIsChecking(true);
10
+ try {
11
+ const result = await mantaClient.request({
12
+ document: DetectMemoryConflictsDocument,
13
+ variables: {
14
+ input: {
15
+ label: input.label,
16
+ description: input.description,
17
+ scope: input.scope,
18
+ teams: input.scope === GQLMemoryScope.Team ? (input.teams ?? []) : undefined,
19
+ excludeIri: input.excludeIri ?? undefined,
20
+ wantToStopAfterMs: conflictCheckTimeoutMs,
21
+ },
22
+ },
23
+ signal: AbortSignal.timeout(conflictCheckTimeoutMs + 5_000),
24
+ });
25
+ return result.detectMemoryConflicts;
26
+ }
27
+ catch {
28
+ return { conflicts: [], timedOut: false };
29
+ }
30
+ finally {
31
+ setIsChecking(false);
32
+ }
33
+ }, [mantaClient]);
34
+ return { check, isChecking };
35
+ }
@@ -0,0 +1,11 @@
1
+ import type { GQLConflictingMemory, GQLMemory } from "@manta-eu/client";
2
+ export type DuplicateMatches = Map<string, GQLConflictingMemory[]>;
3
+ export declare function pickDuplicateTargets(memories: GQLMemory[], max?: number): GQLMemory[];
4
+ export declare function useDuplicateDetection(memories: GQLMemory[], options?: {
5
+ enabled?: boolean;
6
+ max?: number;
7
+ }): {
8
+ duplicates: DuplicateMatches;
9
+ isDetecting: boolean;
10
+ };
11
+ //# sourceMappingURL=useDuplicateDetection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDuplicateDetection.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/hooks/useDuplicateDetection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAKxE,MAAM,MAAM,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;AAOnE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,GAAG,GAAE,MAAyB,GAAG,SAAS,EAAE,CAEvG;AAeD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD;IAAE,UAAU,EAAE,gBAAgB,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAyDxD"}
@@ -0,0 +1,73 @@
1
+ import { isPresent } from "@manta-eu/lib/present";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { useConflictCheck } from "./useConflictCheck.js";
4
+ // Caps how many memories run semantic detection in one pass, so a large unreviewed queue
5
+ // cannot fan out into an unbounded number of detection calls.
6
+ const defaultMaxChecks = 25;
7
+ // Only memories with a description carry enough signal for semantic comparison.
8
+ export function pickDuplicateTargets(memories, max = defaultMaxChecks) {
9
+ return memories.filter((m) => isPresent(m.description)).slice(0, max);
10
+ }
11
+ function buildMemoryKey(memory) {
12
+ return `${memory.iri}:${memory.scope}:${memory.label}:${memory.description ?? ""}`;
13
+ }
14
+ function targetSignature(memories) {
15
+ return memories.map(buildMemoryKey).join("|");
16
+ }
17
+ // Runs the existing semantic conflict check (SEMSIM recall pre-filter + LLM precision judge)
18
+ // across a set of memories and returns, per memory IRI, the existing memories it likely
19
+ // duplicates. Results are cached by IRI+label+description so re-renders and tab switches do
20
+ // not re-issue detection for unchanged memories. Nothing is mutated — this only surfaces
21
+ // candidates; the user still confirms any supersession in the review dialog.
22
+ export function useDuplicateDetection(memories, options = {}) {
23
+ const { enabled = true, max = defaultMaxChecks } = options;
24
+ const { check } = useConflictCheck();
25
+ const targets = useMemo(() => (enabled ? pickDuplicateTargets(memories, max) : []), [memories, enabled, max]);
26
+ const signature = useMemo(() => targetSignature(targets), [targets]);
27
+ const [duplicates, setDuplicates] = useState(new Map());
28
+ const [isDetecting, setIsDetecting] = useState(false);
29
+ const cacheRef = useRef(new Map());
30
+ const checkRef = useRef(check);
31
+ checkRef.current = check;
32
+ const targetsRef = useRef(targets);
33
+ targetsRef.current = targets;
34
+ useEffect(() => {
35
+ const current = targetsRef.current;
36
+ if (!isPresent(current)) {
37
+ setDuplicates(new Map());
38
+ setIsDetecting(false);
39
+ return;
40
+ }
41
+ let cancelled = false;
42
+ setIsDetecting(true);
43
+ void (async () => {
44
+ const next = new Map();
45
+ for (const memory of current) {
46
+ const key = buildMemoryKey(memory);
47
+ let conflicts = cacheRef.current.get(key);
48
+ if (conflicts == null) {
49
+ const result = await checkRef.current({
50
+ label: memory.label,
51
+ description: memory.description ?? "",
52
+ scope: memory.scope,
53
+ excludeIri: memory.iri,
54
+ });
55
+ if (cancelled)
56
+ return;
57
+ conflicts = result.conflicts;
58
+ cacheRef.current.set(key, conflicts);
59
+ }
60
+ if (isPresent(conflicts))
61
+ next.set(memory.iri, conflicts);
62
+ }
63
+ if (!cancelled) {
64
+ setDuplicates(next);
65
+ setIsDetecting(false);
66
+ }
67
+ })();
68
+ return () => {
69
+ cancelled = true;
70
+ };
71
+ }, [signature]);
72
+ return { duplicates, isDetecting };
73
+ }
@@ -0,0 +1,23 @@
1
+ import { type SparqlJsonResults } from "@manta-eu/client/types/sparql-types";
2
+ export declare const liveContextSelectQuery = "SELECT ?entity ?property ?value WHERE {\n :LiveContext_Chat :includes ?entity .\n ?entity ?property ?value .\n FILTER NOT EXISTS {\n ?entity a :Memory .\n {\n ?entity :memoryTrustedUntil ?horizon .\n FILTER(?horizon <= NOW())\n } UNION {\n ?entity :memoryValidUntil ?expiry .\n FILTER(?expiry <= NOW())\n } UNION {\n ?entity :memoryValidFrom ?validFrom .\n FILTER(?validFrom > NOW())\n }\n }\n}";
3
+ export type EntityProperty = {
4
+ predicate: string;
5
+ value: string;
6
+ isUri: boolean;
7
+ datatype?: string;
8
+ };
9
+ export type LiveContextEntity = {
10
+ iri: string;
11
+ compactedIri: string;
12
+ types: string[];
13
+ properties: EntityProperty[];
14
+ };
15
+ export type LiveContextGroup = {
16
+ type: string;
17
+ typeLabel: string;
18
+ entities: LiveContextEntity[];
19
+ };
20
+ export declare function parseLiveContext(data: SparqlJsonResults): LiveContextGroup[];
21
+ export declare const liveContextQueryKey: readonly ["live-context"];
22
+ export declare function useLiveContext(): import("@tanstack/react-query").UseQueryResult<LiveContextGroup[], Error>;
23
+ //# sourceMappingURL=useLiveContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveContext.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/hooks/useLiveContext.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAOtH,eAAO,MAAM,sBAAsB,gfAIjC,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,cAAc,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B,CAAC;AAkBF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,EAAE,CA+D5E;AAED,eAAO,MAAM,mBAAmB,2BAA4B,CAAC;AAE7D,wBAAgB,cAAc,8EAwB7B"}
@@ -0,0 +1,102 @@
1
+ import { liveContextMemoryDateFilter } from "@manta-eu/client/shared/live-context";
2
+ import { compactUri, prependMissingSparqlPrefixes } from "@manta-eu/client/shared/rdf-namespaces";
3
+ import { isSparqlJsonResults } from "@manta-eu/client/types/sparql-types";
4
+ import { useQuery } from "@tanstack/react-query";
5
+ import { useMantaClient } from "#providers/index";
6
+ const rdfTypeIri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
7
+ const trivialTypePrefixes = ["rdf:", "rdfs:", "owl:", "xsd:"];
8
+ export const liveContextSelectQuery = `SELECT ?entity ?property ?value WHERE {
9
+ :LiveContext_Chat :includes ?entity .
10
+ ?entity ?property ?value .
11
+ ${liveContextMemoryDateFilter}
12
+ }`;
13
+ function formatTypeLabel(compacted) {
14
+ const localName = compacted.includes(":") ? (compacted.split(":")[1] ?? compacted) : compacted;
15
+ return localName.replace(/([A-Z])/g, " $1").trim();
16
+ }
17
+ function sparqlValueIsUri(node) {
18
+ return node.type === "uri";
19
+ }
20
+ function sparqlValueDatatype(node) {
21
+ if ("datatype" in node && typeof node.datatype === "string") {
22
+ return node.datatype;
23
+ }
24
+ return undefined;
25
+ }
26
+ export function parseLiveContext(data) {
27
+ const entityMap = new Map();
28
+ for (const binding of data.results.bindings) {
29
+ const entityNode = binding["entity"];
30
+ const propertyNode = binding["property"];
31
+ const valueNode = binding["value"];
32
+ if (!entityNode || !propertyNode || !valueNode)
33
+ continue;
34
+ const entityIri = entityNode.value;
35
+ const propertyIri = propertyNode.value;
36
+ if (!entityMap.has(entityIri)) {
37
+ entityMap.set(entityIri, { types: [], properties: [] });
38
+ }
39
+ const entry = entityMap.get(entityIri);
40
+ if (!entry)
41
+ continue;
42
+ if (propertyIri === rdfTypeIri) {
43
+ const compacted = compactUri(valueNode.value);
44
+ if (!trivialTypePrefixes.some((p) => compacted.startsWith(p))) {
45
+ if (!entry.types.includes(compacted)) {
46
+ entry.types.push(compacted);
47
+ }
48
+ }
49
+ }
50
+ else {
51
+ const isUri = sparqlValueIsUri(valueNode);
52
+ entry.properties.push({
53
+ predicate: compactUri(propertyIri),
54
+ value: isUri ? compactUri(valueNode.value) : valueNode.value,
55
+ isUri,
56
+ datatype: sparqlValueDatatype(valueNode),
57
+ });
58
+ }
59
+ }
60
+ const groupMap = new Map();
61
+ for (const [iri, { types, properties }] of entityMap) {
62
+ const primaryType = types[0] ?? "Unknown";
63
+ if (!groupMap.has(primaryType)) {
64
+ groupMap.set(primaryType, {
65
+ type: primaryType,
66
+ typeLabel: formatTypeLabel(primaryType),
67
+ entities: [],
68
+ });
69
+ }
70
+ const group = groupMap.get(primaryType);
71
+ if (!group)
72
+ continue;
73
+ group.entities.push({
74
+ iri,
75
+ compactedIri: compactUri(iri),
76
+ types,
77
+ properties: [...properties].sort((a, b) => a.predicate.localeCompare(b.predicate)),
78
+ });
79
+ }
80
+ return [...groupMap.values()].sort((a, b) => a.typeLabel.localeCompare(b.typeLabel));
81
+ }
82
+ export const liveContextQueryKey = ["live-context"];
83
+ export function useLiveContext() {
84
+ const { sparqlFetch, onUnauthorized } = useMantaClient();
85
+ return useQuery({
86
+ queryKey: liveContextQueryKey,
87
+ queryFn: async () => {
88
+ const response = await sparqlFetch(prependMissingSparqlPrefixes(liveContextSelectQuery));
89
+ if (!response.ok) {
90
+ if (response.status === 401) {
91
+ onUnauthorized();
92
+ }
93
+ throw new Error(`SPARQL query failed: ${response.status}`);
94
+ }
95
+ const raw = await response.json();
96
+ if (!isSparqlJsonResults(raw)) {
97
+ throw new Error("Invalid SPARQL results format");
98
+ }
99
+ return parseLiveContext(raw);
100
+ },
101
+ });
102
+ }
@@ -0,0 +1,33 @@
1
+ import { type GQLConflictingMemory, type GQLMemory, type GQLMemorySchema } from "@manta-eu/client";
2
+ import type { ColumnDef } from "@tanstack/react-table";
3
+ export declare const memoryColumnIds: {
4
+ readonly label: "label";
5
+ readonly description: "description";
6
+ readonly kind: "kind";
7
+ readonly teams: "teams";
8
+ readonly used: "used";
9
+ readonly actions: "actions";
10
+ };
11
+ export type MemoryColumnId = (typeof memoryColumnIds)[keyof typeof memoryColumnIds];
12
+ export declare const memoryColumnLabels: {
13
+ label: string;
14
+ description: string;
15
+ kind: string;
16
+ teams: string;
17
+ used: string;
18
+ };
19
+ export declare const defaultColumnOrder: string[];
20
+ type UseMemoryColumnsArgs = {
21
+ isOperator?: boolean;
22
+ userId: string;
23
+ schemas?: GQLMemorySchema[];
24
+ onEdit: (memory: GQLMemory) => void;
25
+ onDelete: (iri: string) => void;
26
+ onMove?: (memory: GQLMemory) => void;
27
+ onRestore?: (iri: string) => void;
28
+ onReconfirm?: (iri: string) => void;
29
+ duplicates?: Map<string, GQLConflictingMemory[]>;
30
+ };
31
+ export declare function useMemoryColumns(args: UseMemoryColumnsArgs): ColumnDef<GQLMemory>[];
32
+ export {};
33
+ //# sourceMappingURL=useMemoryColumns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMemoryColumns.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/hooks/useMemoryColumns.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAInG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AA2BvD,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,OAAO,eAAe,CAAC,CAAC;AAGpF,eAAO,MAAM,kBAAkB;;;;;;CAMkB,CAAC;AAElD,eAAO,MAAM,kBAAkB,UAW9B,CAAC;AAyBF,KAAK,oBAAoB,GAAG;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;CAClD,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,CA8PnF"}
@@ -0,0 +1,188 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { isTrustedUntilExpiringSoon } from "@manta-eu/client/shared/memory-preload-gate";
3
+ import { formatEntityName } from "@manta-eu/client/shared/rdf-namespaces";
4
+ import { isPresent } from "@manta-eu/lib/present";
5
+ import { addDays, format, formatDistanceToNow, isBefore } from "date-fns";
6
+ import { ChevronDown, Clock } from "lucide-react";
7
+ import { useMemo } from "react";
8
+ import { AutoCapturedBadge, DuplicateBadge, KindBadge, MemoryAbout, MemoryEvidence, OutOfWindowBadge, PreloadedBadge, SchemaBadge, } from "../components/badges.js";
9
+ import { ImportanceIcon } from "../components/ImportanceSlider.js";
10
+ import { MemoryActions } from "../components/MemoryActions.js";
11
+ import { compareMemoryHorizons, formatHorizonDate, formatHorizonTooltip, memoryHorizon, memoryWindowState, shouldShowValidFrom, } from "../expiry-utils.js";
12
+ import { Tooltip, TooltipContent, TooltipTrigger } from "#components/tooltip/index";
13
+ export const memoryColumnIds = {
14
+ label: "label",
15
+ description: "description",
16
+ kind: "kind",
17
+ teams: "teams",
18
+ used: "used",
19
+ actions: "actions",
20
+ };
21
+ export const memoryColumnLabels = {
22
+ [memoryColumnIds.label]: "Label",
23
+ [memoryColumnIds.description]: "Description",
24
+ [memoryColumnIds.kind]: "Type",
25
+ [memoryColumnIds.teams]: "Teams",
26
+ [memoryColumnIds.used]: "Used",
27
+ };
28
+ export const defaultColumnOrder = [
29
+ memoryColumnIds.label,
30
+ memoryColumnIds.description,
31
+ memoryColumnIds.kind,
32
+ memoryColumnIds.teams,
33
+ "importance",
34
+ "memoryValidUntil",
35
+ "createdBy",
36
+ "extractedAt",
37
+ memoryColumnIds.used,
38
+ memoryColumnIds.actions,
39
+ ];
40
+ function getTeamName(path) {
41
+ return path.split("/").filter(Boolean).pop() ?? path;
42
+ }
43
+ function formatCreatedBy(createdBy, currentUserId) {
44
+ if (!createdBy)
45
+ return "Manta";
46
+ if (createdBy === currentUserId)
47
+ return "You";
48
+ return "Another user";
49
+ }
50
+ function MaybeTooltip(props) {
51
+ const { tooltip, children } = props;
52
+ if (tooltip == null)
53
+ return children;
54
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: children }), _jsx(TooltipContent, { children: tooltip })] }));
55
+ }
56
+ export function useMemoryColumns(args) {
57
+ const { isOperator, userId, schemas, onEdit, onDelete, onMove, onRestore, onReconfirm, duplicates } = args;
58
+ return useMemo(() => {
59
+ const schemaByIri = new Map(schemas?.map((s) => [s.iri, s]) ?? []);
60
+ return [
61
+ {
62
+ id: memoryColumnIds.label,
63
+ accessorKey: "label",
64
+ header: "Label",
65
+ enableSorting: false,
66
+ meta: { className: "max-w-72" },
67
+ cell: ({ row }) => {
68
+ const windowState = memoryWindowState(row.original.memoryValidFrom, row.original.memoryValidUntil);
69
+ return (_jsxs("span", { className: "flex min-w-48 flex-wrap items-start gap-1.5 whitespace-normal typography-caption-medium text-default-foreground", children: [_jsx("span", { className: "line-clamp-2 min-w-24 max-w-full break-words", children: row.original.label }), row.original.supersededBy != null && (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 typography-tiny bg-faint text-muted-foreground border border-muted-border", children: "Archived" })), windowState === "active" ? (_jsx(PreloadedBadge, { memory: row.original })) : (_jsx(OutOfWindowBadge, { state: windowState })), row.original.confidence != null && row.original.confidence < 1 && (_jsx(AutoCapturedBadge, { confidence: row.original.confidence })), duplicates?.get(row.original.iri) != null && (_jsx(DuplicateBadge, { matches: (duplicates.get(row.original.iri) ?? []).map((c) => ({ label: c.label, reason: c.reason })) }))] }));
70
+ },
71
+ },
72
+ {
73
+ id: memoryColumnIds.description,
74
+ accessorKey: "description",
75
+ header: "Description",
76
+ enableSorting: false,
77
+ meta: { className: "max-w-96" },
78
+ cell: ({ row }) => (_jsxs("span", { className: "flex w-full min-w-56 flex-col", children: [_jsx("span", { className: "text-muted-foreground line-clamp-5 whitespace-normal break-words", children: row.original.description }), _jsx(MemoryAbout, { aboutEntityIris: row.original.aboutEntityIris }), _jsx(MemoryEvidence, { evidence: row.original.memoryEvidence })] })),
79
+ },
80
+ {
81
+ id: memoryColumnIds.kind,
82
+ accessorKey: "kind",
83
+ header: "Type",
84
+ enableSorting: true,
85
+ meta: { className: "max-w-52" },
86
+ filterFn: (row, _columnId, filterValue) => row.original.memorySubclass === filterValue || row.original.kind === filterValue,
87
+ cell: ({ row }) => {
88
+ const props = row.original.customProperties;
89
+ const filledEntries = props ? Object.entries(props).filter(([, v]) => isPresent(v)) : [];
90
+ const schema = row.original.memorySubclass ? schemaByIri.get(row.original.memorySubclass) : undefined;
91
+ const schemaLabel = row.original.memorySubclass
92
+ ? (schema?.label ?? formatEntityName(row.original.memorySubclass))
93
+ : null;
94
+ const badges = (_jsxs(_Fragment, { children: [_jsx(KindBadge, { kind: row.original.kind }), _jsx(SchemaBadge, { label: schemaLabel })] }));
95
+ if (!isPresent(filledEntries)) {
96
+ return _jsx("div", { className: "flex min-w-36 flex-wrap items-center gap-1.5", children: badges });
97
+ }
98
+ return (_jsx("div", { className: "flex min-w-36 flex-wrap items-center gap-1.5", children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "inline-flex w-fit flex-wrap items-center gap-1.5", children: [badges, _jsxs("span", { className: "inline-flex items-center gap-0.5 rounded-full px-2 py-0.5 typography-tiny bg-faint border border-muted-border text-muted-foreground", children: [filledEntries.length, _jsx(ChevronDown, { className: "size-3" })] })] }) }), _jsx(TooltipContent, { className: "typography-small text-left max-w-sm", children: _jsx("div", { className: "flex flex-col gap-1", children: filledEntries.map(([path, value]) => {
99
+ const propDef = schema?.properties.find((p) => p.path === path);
100
+ const label = propDef?.label ?? formatEntityName(path);
101
+ return (_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("span", { className: "text-muted-foreground shrink-0 whitespace-nowrap", children: [label, ":"] }), _jsx("span", { className: "min-w-0 truncate", children: value })] }, path));
102
+ }) }) })] }) }));
103
+ },
104
+ },
105
+ {
106
+ id: memoryColumnIds.teams,
107
+ accessorKey: "teams",
108
+ header: "Teams",
109
+ enableSorting: false,
110
+ cell: ({ row }) => {
111
+ const teams = row.original.teams;
112
+ if (!isPresent(teams))
113
+ return _jsx("span", { className: "typography-small text-muted-foreground", children: "-" });
114
+ if (teams.length === 1) {
115
+ return _jsx("span", { className: "typography-small text-muted-foreground", children: getTeamName(teams[0] ?? "") });
116
+ }
117
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("span", { className: "typography-small text-muted-foreground cursor-default", children: [teams.length, " teams"] }) }), _jsx(TooltipContent, { children: _jsx("div", { className: "flex flex-col gap-1", children: teams.map((path) => (_jsx("span", { children: getTeamName(path) }, path))) }) })] }));
118
+ },
119
+ },
120
+ {
121
+ id: "importance",
122
+ accessorKey: "importance",
123
+ header: "Importance",
124
+ enableSorting: true,
125
+ cell: ({ row }) => _jsx(ImportanceIcon, { value: row.original.importance }),
126
+ },
127
+ {
128
+ id: "memoryValidUntil",
129
+ accessorKey: "memoryValidUntil",
130
+ header: "Expires",
131
+ enableSorting: true,
132
+ sortingFn: (a, b) => compareMemoryHorizons(memoryHorizon(a.original.memoryValidUntil, a.original.memoryTrustedUntil), memoryHorizon(b.original.memoryValidUntil, b.original.memoryTrustedUntil)),
133
+ cell: ({ row }) => {
134
+ const horizon = memoryHorizon(row.original.memoryValidUntil, row.original.memoryTrustedUntil);
135
+ const expiresSoon = horizon.kind === "expiry"
136
+ ? isBefore(new Date(horizon.at), addDays(new Date(), 7))
137
+ : horizon.kind === "trust" && isTrustedUntilExpiringSoon(horizon.at, new Date());
138
+ return (_jsx(MaybeTooltip, { tooltip: horizon.kind === "none" ? null : formatHorizonTooltip(horizon), children: _jsxs("span", { className: `inline-flex items-center gap-1 typography-small ${expiresSoon ? "text-warning-foreground" : "text-muted-foreground"}`, children: [_jsx(Clock, { className: "size-3 shrink-0" }), formatHorizonDate(horizon)] }) }));
139
+ },
140
+ },
141
+ {
142
+ id: "createdBy",
143
+ accessorKey: "createdBy",
144
+ header: "Owner",
145
+ enableSorting: false,
146
+ cell: ({ row }) => (_jsx("span", { className: "typography-small text-muted-foreground", children: formatCreatedBy(row.original.createdBy, userId) })),
147
+ },
148
+ {
149
+ id: memoryColumnIds.used,
150
+ accessorFn: (memory) => memory.memoryUseCount + memory.memoryCiteCount,
151
+ header: "Used",
152
+ enableSorting: true,
153
+ cell: ({ row }) => {
154
+ const preloaded = row.original.memoryUseCount;
155
+ const cited = row.original.memoryCiteCount;
156
+ const count = preloaded + cited;
157
+ const lastUsedAt = row.original.memoryLastUsedAt;
158
+ if (!count) {
159
+ return _jsx("span", { className: "typography-small text-muted-foreground whitespace-nowrap", children: "Never" });
160
+ }
161
+ const lastUsedLine = lastUsedAt
162
+ ? `Last used ${formatDistanceToNow(new Date(lastUsedAt), { addSuffix: true })}`
163
+ : null;
164
+ return (_jsx(MaybeTooltip, { tooltip: _jsxs(_Fragment, { children: [_jsxs("div", { children: [preloaded, "\u00D7 pre-loaded, ", cited, "\u00D7 cited"] }), lastUsedLine ? _jsx("div", { children: lastUsedLine }) : null] }), children: _jsxs("span", { className: "typography-small whitespace-nowrap", children: [count, "\u00D7"] }) }));
165
+ },
166
+ },
167
+ {
168
+ id: "extractedAt",
169
+ accessorKey: "updatedAt",
170
+ header: "Updated",
171
+ enableSorting: true,
172
+ cell: ({ row }) => {
173
+ const validFrom = row.original.memoryValidFrom;
174
+ const tooltip = validFrom && shouldShowValidFrom(row.original.updatedAt, validFrom)
175
+ ? `True since ${format(new Date(validFrom), "MMM d, yyyy")} — older than this record`
176
+ : null;
177
+ return (_jsx(MaybeTooltip, { tooltip: tooltip, children: _jsx("span", { className: "typography-small text-muted-foreground whitespace-nowrap", children: formatDistanceToNow(new Date(row.original.updatedAt), { addSuffix: true }) }) }));
178
+ },
179
+ },
180
+ {
181
+ id: memoryColumnIds.actions,
182
+ enableHiding: false,
183
+ enableSorting: false,
184
+ cell: ({ row }) => (_jsx(MemoryActions, { memory: row.original, isOperator: isOperator, onEdit: onEdit, onDelete: onDelete, onMove: onMove, onRestore: onRestore, onReconfirm: onReconfirm })),
185
+ },
186
+ ];
187
+ }, [isOperator, userId, schemas, onEdit, onDelete, onMove, onRestore, onReconfirm, duplicates]);
188
+ }
@@ -0,0 +1,33 @@
1
+ import type { GQLMemory } from "@manta-eu/client";
2
+ import type { ColumnDef, SortingState, Table } from "@tanstack/react-table";
3
+ import type { KindFilter, SchemaFilter } from "../components/MemoriesFilters.js";
4
+ export type { KindFilter, SchemaFilter };
5
+ export type ImportanceFilter = 0 | 1 | 2 | 3 | 4 | 5;
6
+ export type StatusFilterKey = "autoCaptured" | "hideStale" | "promotion" | "deadWeight" | "unused" | "needsReview";
7
+ export type MemoryFilterCriteria = {
8
+ search: string;
9
+ importance: ImportanceFilter;
10
+ autoCaptured: boolean;
11
+ hideStale: boolean;
12
+ promotion: boolean;
13
+ deadWeight: boolean;
14
+ unused: boolean;
15
+ needsReview: boolean;
16
+ schema: SchemaFilter;
17
+ };
18
+ export declare function filterMemories(data: GQLMemory[], criteria: MemoryFilterCriteria, now?: Date): GQLMemory[];
19
+ export type UseMemoryTableResult = {
20
+ table: Table<GQLMemory>;
21
+ kindFilter: KindFilter;
22
+ onKindFilterChange: (kind: KindFilter) => void;
23
+ schemaFilter: SchemaFilter;
24
+ onSchemaFilterChange: (iri: SchemaFilter) => void;
25
+ searchQuery: string;
26
+ onSearchQueryChange: (query: string) => void;
27
+ importanceFilter: ImportanceFilter;
28
+ onImportanceFilterChange: (importance: ImportanceFilter) => void;
29
+ statusFilters: Record<StatusFilterKey, boolean>;
30
+ onStatusFilterChange: (key: StatusFilterKey, value: boolean) => void;
31
+ };
32
+ export declare function useMemoryTable(tableKey: string, data: GQLMemory[], columns: ColumnDef<GQLMemory>[], initialSorting?: SortingState, initialColumnVisibility?: Record<string, boolean>): UseMemoryTableResult;
33
+ //# sourceMappingURL=useMemoryTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMemoryTable.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/hooks/useMemoryTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAOlD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAM7F,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAK9E,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAEzC,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAErD,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,QAAQ,GAAG,aAAa,CAAC;AA0BnH,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,oBAAoB,EAAE,GAAG,GAAE,IAAiB,GAAG,SAAS,EAAE,CAgCrH;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACxB,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,YAAY,CAAC;IAC3B,oBAAoB,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,wBAAwB,EAAE,CAAC,UAAU,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjE,aAAa,EAAE,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAChD,oBAAoB,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACtE,CAAC;AAEF,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,SAAS,EAAE,EACjB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,EAC/B,cAAc,GAAE,YAAiB,EACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChD,oBAAoB,CAiGtB"}