@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,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { GQLMemoryScope } from "@manta-eu/client";
3
+ import { isPresent } from "@manta-eu/lib/present";
4
+ import { match } from "ts-pattern";
5
+ import { formatHorizonRelative, isTrustExpired, memoryHorizon } from "../expiry-utils.js";
6
+ import { KindBadge } from "./badges.js";
7
+ import { Badge } from "#components/badge/index";
8
+ import { Checkbox } from "#components/checkbox/index";
9
+ import { cn } from "#lib/utils";
10
+ const importanceLabels = {
11
+ 1: "Disabled",
12
+ 2: "Low importance",
13
+ 3: "Medium importance",
14
+ 4: "High importance",
15
+ 5: "Critical",
16
+ };
17
+ const importanceDotClass = {
18
+ 1: "bg-muted-foreground/40",
19
+ 2: "bg-muted-foreground",
20
+ 3: "bg-default-foreground/50",
21
+ 4: "bg-warning-foreground",
22
+ 5: "bg-error-foreground",
23
+ };
24
+ function formatAuthor(createdBy, currentUserId) {
25
+ if (isPresent(currentUserId) && createdBy === currentUserId)
26
+ return "You";
27
+ return "Another user";
28
+ }
29
+ function MetaSeparator() {
30
+ return _jsx("span", { className: "text-muted-border", children: "\u00B7" });
31
+ }
32
+ export function ConflictMemoryCard(props) {
33
+ const { conflict, scope, checked, onToggleChecked, showMerge, merging, onToggleMerge, currentUserId } = props;
34
+ const showAuthor = scope !== GQLMemoryScope.User && isPresent(conflict.createdBy);
35
+ const horizon = memoryHorizon(conflict.memoryValidUntil, conflict.memoryTrustedUntil);
36
+ const unconfirmed = isTrustExpired(conflict.memoryTrustedUntil);
37
+ const horizonLabel = match(horizon)
38
+ .with({ kind: "none" }, () => null)
39
+ .with({ kind: "trust" }, (trust) => (unconfirmed ? null : formatHorizonRelative(trust)))
40
+ .with({ kind: "expiry" }, (expiry) => formatHorizonRelative(expiry))
41
+ .exhaustive();
42
+ return (_jsxs("div", { className: "flex flex-col gap-2 rounded-lg border border-muted-border p-3", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(Checkbox, { checked: checked, onCheckedChange: onToggleChecked, className: "mt-0.5 shrink-0" }), _jsxs("div", { className: "flex flex-col gap-1.5 flex-1 min-w-0", children: [_jsx("span", { className: "typography-caption-medium text-default-foreground", children: conflict.label }), conflict.description && (_jsx("span", { className: "typography-small text-muted-foreground line-clamp-2", children: conflict.description })), conflict.reason && _jsx("span", { className: "typography-tiny text-accent-foreground italic", children: conflict.reason }), _jsxs("div", { className: "flex items-center gap-1.5 flex-wrap typography-tiny text-muted-foreground mt-0.5", children: [_jsx(KindBadge, { kind: conflict.kind }), _jsxs(Badge, { size: "sm", variant: "secondary", className: "capitalize", children: [_jsx("span", { className: cn("size-1.5 rounded-full shrink-0", importanceDotClass[conflict.importance]) }), importanceLabels[conflict.importance] ?? "Medium importance"] }), unconfirmed && (_jsxs(_Fragment, { children: [_jsx(MetaSeparator, {}), _jsx("span", { className: "text-warning-foreground", children: "Unconfirmed \u2014 no longer pre-loaded" })] })), horizonLabel && (_jsxs(_Fragment, { children: [_jsx(MetaSeparator, {}), _jsx("span", { children: horizonLabel })] })), showAuthor && (_jsxs(_Fragment, { children: [_jsx(MetaSeparator, {}), _jsxs("span", { children: ["Added by ", formatAuthor(conflict.createdBy, currentUserId)] })] }))] })] })] }), showMerge && isPresent(conflict.currentTeams) && (_jsxs("div", { className: "ml-8 flex flex-col gap-1.5", children: [_jsx("div", { className: "flex flex-wrap gap-1", children: conflict.currentTeams.map((g) => (_jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 typography-tiny bg-muted text-muted-foreground", children: g.replace(/^\//, "") }, g))) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { checked: merging, onCheckedChange: onToggleMerge, disabled: !checked }), _jsx("span", { className: "typography-small text-muted-foreground", children: "Merge teams (union of old + new teams)" })] })] }))] }));
43
+ }
@@ -0,0 +1,7 @@
1
+ export type ConflictTimeoutFooterProps = {
2
+ onCancel: () => void;
3
+ onConfirm: () => void;
4
+ isSaving: boolean;
5
+ };
6
+ export declare function ConflictTimeoutFooter(props: ConflictTimeoutFooterProps): import("react/jsx-runtime").JSX.Element;
7
+ //# sourceMappingURL=ConflictTimeoutFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConflictTimeoutFooter.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/ConflictTimeoutFooter.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,2CAatE"}
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "#components/button/index";
3
+ export function ConflictTimeoutFooter(props) {
4
+ const { onCancel, onConfirm, isSaving } = props;
5
+ return (_jsxs(_Fragment, { children: [_jsx("p", { className: "typography-small text-muted-foreground mr-auto", children: "Conflict check timed out. Save without checking?" }), _jsx(Button, { variant: "tertiary", onClick: onCancel, disabled: isSaving, children: "Cancel" }), _jsx(Button, { onClick: onConfirm, disabled: isSaving, children: isSaving ? "Saving…" : "Save anyway" })] }));
6
+ }
@@ -0,0 +1,61 @@
1
+ export type ConsolidationMemoryView = {
2
+ iri: string;
3
+ label: string;
4
+ description?: string | null;
5
+ teams?: readonly string[] | null;
6
+ };
7
+ export type ReviewProposalKind = "duplicate" | "pattern";
8
+ export type ConsolidationClusterView = {
9
+ memories: ConsolidationMemoryView[];
10
+ reason: string;
11
+ suggestedLabel: string;
12
+ suggestedDescription: string;
13
+ kind?: ReviewProposalKind;
14
+ };
15
+ export type ConsolidationDecision = {
16
+ memoryIris: string[];
17
+ label: string;
18
+ description: string;
19
+ kind: ReviewProposalKind;
20
+ };
21
+ export type ReviewCopy = {
22
+ intro: string;
23
+ labelField: string;
24
+ descriptionField: string;
25
+ confirm: string;
26
+ };
27
+ export declare const consolidationCopy: ReviewCopy;
28
+ export declare const abstractionCopy: ReviewCopy;
29
+ export declare function reviewCopyFor(kind: ReviewProposalKind | undefined): ReviewCopy;
30
+ export declare const reviewDialogTitle = "Review redundant memories";
31
+ export declare function consolidationSummary(clusterCount: number, index: number, isLoading: boolean, timedOut?: boolean, failed?: boolean): string;
32
+ export declare function consolidationProgressLabel(candidateCount: number, limit?: number): string;
33
+ export declare function consolidationCoverageNote(comparedCount: number | null | undefined, candidateCount: number, checkCompleted?: boolean): string | null;
34
+ export declare function mergedAudienceNote(memories: readonly ConsolidationMemoryView[]): string | null;
35
+ export declare const consolidationSlowAfterMs = 8000;
36
+ export type ConsolidationProgressProps = {
37
+ candidateCount: number;
38
+ };
39
+ export declare function ConsolidationProgress(props: ConsolidationProgressProps): import("react/jsx-runtime").JSX.Element;
40
+ export type ConsolidationClusterReviewProps = {
41
+ cluster: ConsolidationClusterView;
42
+ label: string;
43
+ description: string;
44
+ onLabelChange: (value: string) => void;
45
+ onDescriptionChange: (value: string) => void;
46
+ };
47
+ export declare function ConsolidationClusterReview(props: ConsolidationClusterReviewProps): import("react/jsx-runtime").JSX.Element;
48
+ export type ConsolidationReviewDialogProps = {
49
+ open: boolean;
50
+ clusters: ConsolidationClusterView[];
51
+ isLoading: boolean;
52
+ isSaving: boolean;
53
+ candidateCount: number;
54
+ comparedCount: number | null;
55
+ timedOut?: boolean;
56
+ errorMessage?: string | null;
57
+ onMerge: (decision: ConsolidationDecision) => void;
58
+ onClose: () => void;
59
+ };
60
+ export declare function ConsolidationReviewDialog(props: ConsolidationReviewDialogProps): import("react/jsx-runtime").JSX.Element;
61
+ //# sourceMappingURL=ConsolidationReviewDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConsolidationReviewDialog.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/ConsolidationReviewDialog.tsx"],"names":[],"mappings":"AAgBA,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,uBAAuB,EAAE,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE,kBAAkB,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,kBAAkB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,UAK/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,UAM7B,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,kBAAkB,GAAG,SAAS,GAAG,UAAU,CAE9E;AAED,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAE7D,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,EAClB,QAAQ,UAAQ,EAChB,MAAM,UAAQ,GACb,MAAM,CAWR;AAED,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,SAA8B,GAAG,MAAM,CAI9G;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,cAAc,EAAE,MAAM,EACtB,cAAc,UAAO,GACpB,MAAM,GAAG,IAAI,CAKf;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,SAAS,uBAAuB,EAAE,GAAG,MAAM,GAAG,IAAI,CAM9F;AAED,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,MAAM,MAAM,0BAA0B,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpE,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,2CAoBtE;AAED,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,wBAAwB,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,+BAA+B,2CAkChF;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,wBAAwB,EAAE,CAAC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAMF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,2CA8F9E"}
@@ -0,0 +1,121 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { consolidationCandidateLimit } from "@manta-eu/client/shared/memory-consolidation-limits";
3
+ import { unionOfTeams } from "@manta-eu/client/shared/memory-teams";
4
+ import { isPresent } from "@manta-eu/lib/present";
5
+ import { useCallback, useEffect, useState } from "react";
6
+ import { Button } from "#components/button/index";
7
+ import { Input, Textarea } from "#components/input/index";
8
+ import { Loader } from "#components/loader/index";
9
+ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "#components/modal/index";
10
+ export const consolidationCopy = {
11
+ intro: "These say the same thing. Merging them loses nothing.",
12
+ labelField: "Merged label",
13
+ descriptionField: "Merged description",
14
+ confirm: "Merge",
15
+ };
16
+ export const abstractionCopy = {
17
+ intro: "These are instances of one broader rule. The general memory replaces them, so anything true of only some of them is lost.",
18
+ labelField: "General label",
19
+ descriptionField: "General description",
20
+ confirm: "Replace with the general memory",
21
+ };
22
+ export function reviewCopyFor(kind) {
23
+ return kind === "pattern" ? abstractionCopy : consolidationCopy;
24
+ }
25
+ export const reviewDialogTitle = "Review redundant memories";
26
+ export function consolidationSummary(clusterCount, index, isLoading, timedOut = false, failed = false) {
27
+ if (isLoading)
28
+ return "Looking for memories that say the same thing, and for patterns worth stating once…";
29
+ if (clusterCount > 0 && (timedOut || failed)) {
30
+ const stopped = timedOut ? "ran out of time" : "could not finish";
31
+ return `The check ${stopped}, but found ${clusterCount} ${clusterCount === 1 ? "group" : "groups"} before stopping. Group ${index + 1} of ${clusterCount}.`;
32
+ }
33
+ if (timedOut)
34
+ return "The check ran out of time, so nothing was compared. Try again on a smaller scope.";
35
+ if (failed)
36
+ return "The check could not finish, so nothing was compared.";
37
+ if (clusterCount === 0)
38
+ return "Nothing to clean up. Every memory in this scope is distinct and specific to itself.";
39
+ if (index >= clusterCount)
40
+ return `You have reviewed all ${clusterCount} groups.`;
41
+ return `Group ${index + 1} of ${clusterCount}.`;
42
+ }
43
+ export function consolidationProgressLabel(candidateCount, limit = consolidationCandidateLimit) {
44
+ if (candidateCount <= 0)
45
+ return "Comparing your memories…";
46
+ if (candidateCount > limit)
47
+ return `Comparing ${limit} of ${candidateCount} memories…`;
48
+ return `Comparing ${candidateCount} memories…`;
49
+ }
50
+ export function consolidationCoverageNote(comparedCount, candidateCount, checkCompleted = true) {
51
+ if (!checkCompleted || comparedCount == null)
52
+ return null;
53
+ if (candidateCount < 2)
54
+ return null;
55
+ if (comparedCount >= candidateCount)
56
+ return null;
57
+ return `${comparedCount} of ${candidateCount} memories were compared; the rest had nothing resembling them.`;
58
+ }
59
+ export function mergedAudienceNote(memories) {
60
+ const perMemory = memories.map((m) => new Set(m.teams ?? []));
61
+ const union = unionOfTeams(memories.map((m) => m.teams));
62
+ if (!isPresent(union) || perMemory.every((teams) => teams.size === union.length))
63
+ return null;
64
+ return `These are not all shared with the same teams. The merged memory goes to all of them: ${[...union].sort().join(", ")}.`;
65
+ }
66
+ export const consolidationSlowAfterMs = 8_000;
67
+ export function ConsolidationProgress(props) {
68
+ const { candidateCount } = props;
69
+ const [slow, setSlow] = useState(false);
70
+ useEffect(() => {
71
+ const timer = setTimeout(() => setSlow(true), consolidationSlowAfterMs);
72
+ return () => clearTimeout(timer);
73
+ }, []);
74
+ return (_jsxs("div", { className: "flex flex-col items-center gap-3 py-10 text-center", children: [_jsx(Loader, { className: "size-6" }), _jsx("p", { className: "typography-caption-medium text-default-foreground", children: consolidationProgressLabel(candidateCount) }), _jsx("p", { className: "typography-small text-muted-foreground max-w-sm", children: slow
75
+ ? "Still comparing — this can take up to a minute on a large scope."
76
+ : "This usually takes a few seconds." })] }));
77
+ }
78
+ export function ConsolidationClusterReview(props) {
79
+ const { cluster, label, description, onLabelChange, onDescriptionChange } = props;
80
+ const copy = reviewCopyFor(cluster.kind);
81
+ const audienceNote = mergedAudienceNote(cluster.memories);
82
+ return (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx("p", { className: "typography-small-medium text-default-foreground", children: copy.intro }), _jsx("p", { className: "typography-small text-muted-foreground", children: cluster.reason }), audienceNote && _jsx("p", { className: "typography-small text-warning-foreground", children: audienceNote }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("span", { className: "typography-small-medium", children: ["These ", cluster.memories.length, " memories will be replaced by one:"] }), cluster.memories.map((memory) => (_jsxs("div", { className: "rounded-lg border border-muted-border p-3", children: [_jsx("div", { className: "typography-caption-medium text-default-foreground", children: memory.label }), _jsx("div", { className: "typography-small text-muted-foreground", children: memory.description })] }, memory.iri)))] }), _jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "typography-small-medium", children: copy.labelField }), _jsx(Input, { value: label, onChange: (e) => onLabelChange(e.target.value) })] }), _jsxs("label", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "typography-small-medium", children: copy.descriptionField }), _jsx(Textarea, { rows: 3, value: description, onChange: (e) => onDescriptionChange(e.target.value) })] })] }));
83
+ }
84
+ function clusterKey(cluster) {
85
+ return cluster ? cluster.memories.map((m) => m.iri).join("|") : "";
86
+ }
87
+ export function ConsolidationReviewDialog(props) {
88
+ const { open, clusters, isLoading, isSaving, candidateCount, comparedCount, timedOut, errorMessage, onMerge, onClose, } = props;
89
+ const [index, setIndex] = useState(0);
90
+ const [draft, setDraft] = useState({ key: "", label: "", description: "" });
91
+ const current = clusters[index];
92
+ const copy = reviewCopyFor(current?.kind);
93
+ const currentKey = clusterKey(current);
94
+ const coverageNote = consolidationCoverageNote(comparedCount, candidateCount, !isPresent(errorMessage));
95
+ useEffect(() => {
96
+ if (open)
97
+ setIndex(0);
98
+ }, [open]);
99
+ if (draft.key !== currentKey) {
100
+ setDraft({
101
+ key: currentKey,
102
+ label: current?.suggestedLabel ?? "",
103
+ description: current?.suggestedDescription ?? "",
104
+ });
105
+ }
106
+ const { label, description } = draft;
107
+ const setLabel = useCallback((value) => setDraft((d) => ({ ...d, label: value })), []);
108
+ const setDescription = useCallback((value) => setDraft((d) => ({ ...d, description: value })), []);
109
+ const handleMerge = useCallback(() => {
110
+ if (!current)
111
+ return;
112
+ onMerge({
113
+ memoryIris: current.memories.map((m) => m.iri),
114
+ label: label.trim(),
115
+ description: description.trim(),
116
+ kind: current.kind ?? "duplicate",
117
+ });
118
+ }, [current, label, description, onMerge]);
119
+ const handleSkip = useCallback(() => setIndex((i) => Math.min(i + 1, clusters.length)), [clusters.length]);
120
+ return (_jsx(Dialog, { open: open, onOpenChange: (next) => !next && onClose(), children: _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { text: reviewDialogTitle }), _jsx(DialogDescription, { children: consolidationSummary(clusters.length, index, isLoading, timedOut, isPresent(errorMessage)) })] }), errorMessage && _jsx("p", { className: "typography-small text-error-foreground", children: errorMessage }), isLoading && _jsx(ConsolidationProgress, { candidateCount: candidateCount }), !isLoading && coverageNote && _jsx("p", { className: "typography-small text-muted-foreground", children: coverageNote }), !isLoading && current && (_jsx(ConsolidationClusterReview, { cluster: current, label: label, description: description, onLabelChange: setLabel, onDescriptionChange: setDescription })), _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: onClose, children: "Close" }), !isLoading && current && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "secondary", onClick: handleSkip, disabled: isSaving, children: "Skip" }), _jsx(Button, { onClick: handleMerge, disabled: isSaving || !isPresent(label.trim()), children: isSaving ? "Saving…" : `${copy.confirm} (${current.memories.length})` })] }))] })] }) }));
121
+ }
@@ -0,0 +1,18 @@
1
+ export type MemoriesEmptyStateProps = {
2
+ isOperator?: boolean;
3
+ onAdd: () => void;
4
+ };
5
+ export declare function MemoriesEmptyState(props: MemoriesEmptyStateProps): import("react/jsx-runtime").JSX.Element;
6
+ type CompanyMemoriesEmptyStateProps = {
7
+ onAdd: () => void;
8
+ onSetUp: () => void;
9
+ };
10
+ export declare function CompanyMemoriesEmptyState(props: CompanyMemoriesEmptyStateProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function CapturedMemoriesEmptyState(): import("react/jsx-runtime").JSX.Element;
12
+ export type GroupMemoriesEmptyStateProps = {
13
+ isOperator?: boolean;
14
+ onAdd?: () => void;
15
+ };
16
+ export declare function GroupMemoriesEmptyState(props: GroupMemoriesEmptyStateProps): import("react/jsx-runtime").JSX.Element;
17
+ export {};
18
+ //# sourceMappingURL=EmptyStates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmptyStates.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/EmptyStates.tsx"],"names":[],"mappings":"AAKA,MAAM,MAAM,uBAAuB,GAAG;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAchE;AAED,KAAK,8BAA8B,GAAG;IACpC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,2CAmB9E;AAED,wBAAgB,0BAA0B,4CAYzC;AAED,MAAM,MAAM,4BAA4B,GAAG;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,4BAA4B,2CAoB1E"}
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Brain, Building2, MessageSquare, Plus, Users } from "lucide-react";
3
+ import { Link } from "react-router";
4
+ import { Button } from "#components/button/index";
5
+ import { EmptyState } from "#components/empty-state/index";
6
+ export function MemoriesEmptyState(props) {
7
+ const { onAdd } = props;
8
+ return (_jsx(EmptyState, { icon: Brain, title: "No memories yet", description: "Memories help Manta personalize every conversation. Add facts, preferences, or objectives you want Manta to always keep in mind.", children: _jsx(Button, { onClick: onAdd, icon: Plus, children: "Add memory" }) }));
9
+ }
10
+ export function CompanyMemoriesEmptyState(props) {
11
+ const { onAdd, onSetUp } = props;
12
+ return (_jsx(EmptyState, { icon: Building2, title: "No company memories yet", description: "Add shared context that Manta uses for everyone in the company.", children: _jsxs("div", { className: "flex w-full flex-col gap-2 sm:w-auto sm:flex-row", children: [_jsx(Button, { className: "w-full sm:w-auto", onClick: onSetUp, children: "Set up with guided questions" }), _jsx(Button, { className: "w-full sm:w-auto", variant: "ghost", onClick: onAdd, icon: Plus, children: "Add manually" })] }) }));
13
+ }
14
+ export function CapturedMemoriesEmptyState() {
15
+ return (_jsx(EmptyState, { icon: MessageSquare, title: "No captured memories yet", description: "Manta captures useful context from your conversations automatically. Start chatting and memories will appear here.", children: _jsx(Button, { asChild: true, children: _jsx(Link, { to: "/", children: "Start chatting" }) }) }));
16
+ }
17
+ export function GroupMemoriesEmptyState(props) {
18
+ const { isOperator, onAdd } = props;
19
+ return (_jsx(EmptyState, { icon: Users, title: "No team memories yet", description: isOperator
20
+ ? "Add shared context that Manta uses for specific teams in the company."
21
+ : "Your team hasn't added any shared memories yet.", children: onAdd && (_jsx(Button, { onClick: onAdd, icon: Plus, children: "Add team memory" })) }));
22
+ }
@@ -0,0 +1,11 @@
1
+ export type ImportanceSliderProps = {
2
+ value: number;
3
+ onChange: (v: number) => void;
4
+ className?: string;
5
+ };
6
+ export declare function ImportanceSlider(props: ImportanceSliderProps): import("react/jsx-runtime").JSX.Element;
7
+ export type ImportanceIconProps = {
8
+ value: number;
9
+ };
10
+ export declare function ImportanceIcon(props: ImportanceIconProps): import("react/jsx-runtime").JSX.Element | null;
11
+ //# sourceMappingURL=ImportanceSlider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImportanceSlider.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/ImportanceSlider.tsx"],"names":[],"mappings":"AAqBA,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,2CAyC5D;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,kDAYxD"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { isPresent } from "@manta-eu/lib/present";
3
+ import { ChevronDown, ChevronUp, ChevronsUp, Equal, Minus } from "lucide-react";
4
+ import { Slider } from "#components/slider/index";
5
+ import { cn } from "#lib/utils";
6
+ const importanceSteps = [1, 2, 3, 4, 5];
7
+ const importanceConfig = {
8
+ 1: { icon: Minus, className: "text-muted-foreground/50", label: "Disabled" },
9
+ 2: { icon: ChevronDown, className: "text-muted-foreground", label: "Low" },
10
+ 3: { icon: Equal, className: "text-default-foreground/60", label: "Medium" },
11
+ 4: { icon: ChevronUp, className: "text-warning-foreground", label: "High" },
12
+ 5: { icon: ChevronsUp, className: "text-error-foreground", label: "Critical" },
13
+ };
14
+ export function ImportanceSlider(props) {
15
+ const { value, onChange, className } = props;
16
+ return (_jsxs("div", { className: cn("flex flex-col gap-2 w-full", className), onClick: (e) => e.stopPropagation(), children: [_jsx(Slider, { min: 1, max: 5, step: 1, value: [value], onValueChange: (vals) => {
17
+ const v = vals[0];
18
+ if (isPresent(v))
19
+ onChange(v);
20
+ }, className: "w-full", "aria-label": "Importance" }), _jsx("div", { className: "flex justify-between px-2", children: importanceSteps.map((step) => (_jsx("div", { className: cn("w-0 overflow-visible flex", step === 1 ? "justify-start" : step === 5 ? "justify-end" : "justify-center"), children: _jsx("span", { onClick: () => onChange(step), className: cn("whitespace-nowrap cursor-pointer select-none", step === value
21
+ ? "typography-tiny-medium text-default-foreground"
22
+ : "typography-tiny text-muted-foreground hover:text-default-foreground"), children: importanceConfig[step]?.label }) }, step))) })] }));
23
+ }
24
+ export function ImportanceIcon(props) {
25
+ const { value } = props;
26
+ const config = importanceConfig[value];
27
+ if (!config)
28
+ return null;
29
+ const Icon = config.icon;
30
+ return (_jsxs("div", { className: cn("inline-flex items-center gap-1", config.className), "aria-label": `Importance: ${config.label}`, children: [_jsx(Icon, { className: "size-4 shrink-0" }), _jsx("span", { className: "typography-small", children: config.label })] }));
31
+ }
@@ -0,0 +1,6 @@
1
+ type LiveContextTabProps = {
2
+ query?: string;
3
+ };
4
+ export declare function LiveContextTab(props: LiveContextTabProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
6
+ //# sourceMappingURL=LiveContextTab.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LiveContextTab.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/LiveContextTab.tsx"],"names":[],"mappings":"AAQA,KAAK,mBAAmB,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,2CA4CxD"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { humanPlural } from "@manta-eu/lib/humanize";
3
+ import { isPresent } from "@manta-eu/lib/present";
4
+ import { ChevronRight, Layers, TriangleAlert } from "lucide-react";
5
+ import { useLiveContext } from "../hooks/useLiveContext.js";
6
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "#components/collapsible/index";
7
+ import { EmptyState } from "#components/empty-state/index";
8
+ import { Skeleton } from "#components/skeleton/index";
9
+ export function LiveContextTab(props) {
10
+ const { query = "" } = props;
11
+ const { data: groups, isLoading, error } = useLiveContext();
12
+ if (isLoading) {
13
+ return _jsx(LiveContextSkeleton, {});
14
+ }
15
+ if (error) {
16
+ return (_jsx(EmptyState, { icon: TriangleAlert, iconClassName: "text-error-foreground", title: "Failed to load Live Context", description: error instanceof Error ? error.message : "An unexpected error occurred." }));
17
+ }
18
+ if (!isPresent(groups)) {
19
+ return (_jsx(EmptyState, { icon: Layers, title: "No Live Context yet", description: 'Live Context surfaces high-importance company memories and facts. Add company memories with importance "high" or "critical" to see them here.' }));
20
+ }
21
+ const parsedQuery = String(query).trim().toLowerCase();
22
+ const filtered = isPresent(parsedQuery)
23
+ ? groups.filter((g) => g.typeLabel.toLowerCase().includes(parsedQuery))
24
+ : groups;
25
+ return (_jsxs("div", { className: "flex flex-col gap-6 max-w-3xl mx-auto", children: [!isPresent(filtered) && (_jsx(EmptyState, { icon: Layers, title: "No groups match", description: `No groups found for "${query}".` })), filtered.map((group) => (_jsx(EntityGroupSection, { group: group }, group.type)))] }));
26
+ }
27
+ function EntityGroupSection(props) {
28
+ const { group } = props;
29
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "typography-small-medium text-default-foreground", children: group.typeLabel }), _jsx("span", { className: "inline-flex items-center rounded-full px-2 py-0.5 typography-tiny bg-faint text-muted-foreground", children: group.entities.length }), _jsx("span", { className: "typography-tiny text-muted-foreground font-mono", children: group.type })] }), _jsx("div", { className: "flex flex-col rounded-xl border border-muted-border bg-card overflow-hidden divide-y divide-muted-border", children: group.entities.map((entity) => (_jsx(EntityCard, { compactedIri: entity.compactedIri, properties: entity.properties }, entity.iri))) })] }));
30
+ }
31
+ function EntityCard(props) {
32
+ const { compactedIri, properties } = props;
33
+ return (_jsxs(Collapsible, { children: [_jsxs(CollapsibleTrigger, { className: "group flex w-full items-center gap-2 px-4 py-3 text-left hover:bg-faint transition-colors", children: [_jsx(ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" }), _jsx("span", { className: "typography-small font-mono text-default-foreground truncate", children: compactedIri }), _jsxs("span", { className: "ml-auto shrink-0 typography-tiny text-muted-foreground", children: [properties.length, " ", humanPlural("property", properties.length)] })] }), _jsx(CollapsibleContent, { children: _jsx("div", { className: "border-t border-muted-border", children: _jsx("table", { className: "w-full text-left", children: _jsx("tbody", { children: properties.map((prop) => (_jsxs("tr", { className: "border-b border-muted-border last:border-0", children: [_jsx("td", { className: "px-4 py-2 align-top w-52 shrink-0", children: _jsx("span", { className: "typography-tiny font-mono text-muted-foreground", children: prop.predicate }) }), _jsx("td", { className: "px-4 py-2 align-top break-all", children: _jsx("span", { className: `typography-small ${prop.isUri ? "text-accent-foreground font-mono" : "text-default-foreground"}`, children: prop.value }) })] }, prop.predicate))) }) }) }) })] }));
34
+ }
35
+ function LiveContextSkeleton() {
36
+ return (_jsx("div", { className: "flex flex-col gap-6 max-w-3xl mx-auto", children: Array.from({ length: 3 }, (_, i) => (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Skeleton, { className: "h-4 w-32 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-6 rounded-full" })] }), _jsx("div", { className: "rounded-xl border border-muted-border overflow-hidden", children: Array.from({ length: i + 1 }, (_, j) => (_jsxs("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-muted-border last:border-0", children: [_jsx(Skeleton, { className: "size-3.5 rounded-sm" }), _jsx(Skeleton, { className: "h-4 flex-1 rounded-md" })] }, `lc-skel-entity-${i}-${j}`))) })] }, `lc-skel-group-${i}`))) }));
37
+ }
@@ -0,0 +1,2 @@
1
+ export declare function LoadingSkeleton(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=LoadingSkeleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingSkeleton.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/LoadingSkeleton.tsx"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,4CAqB9B"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Skeleton } from "#components/skeleton/index";
3
+ import { TableSkeleton } from "#components/table-skeleton/index";
4
+ const gridColsClassName = "grid-cols-[16fr_24fr_11fr_9fr_7fr_10fr_9fr_10fr_4fr]";
5
+ export function LoadingSkeleton() {
6
+ return (_jsx(TableSkeleton, { gridColsClassName: gridColsClassName, headerColumnCount: 9, rows: 5, renderRow: () => (_jsxs(_Fragment, { children: [_jsx(Skeleton, { className: "h-4 w-3/4 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-5/6 rounded-md" }), _jsx(Skeleton, { className: "h-5 w-3/4 rounded-full" }), _jsx(Skeleton, { className: "h-5 w-2/3 rounded-full" }), _jsx(Skeleton, { className: "size-5 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-3/4 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-2/3 rounded-md" }), _jsx(Skeleton, { className: "h-4 w-3/4 rounded-md" }), _jsx(Skeleton, { className: "size-4 rounded-md" })] })) }));
7
+ }
@@ -0,0 +1,31 @@
1
+ import { GQLMemoryKind, type GQLMemorySchema } from "@manta-eu/client";
2
+ import type { Table } from "@tanstack/react-table";
3
+ import type { ReactNode } from "react";
4
+ import type { ImportanceFilter, StatusFilterKey } from "../hooks/useMemoryTable.js";
5
+ export type KindFilter = "ALL" | GQLMemoryKind;
6
+ export type SchemaFilter = "ALL" | "NONE" | string;
7
+ export declare const kindFilterOptions: {
8
+ id: KindFilter;
9
+ label: string;
10
+ }[];
11
+ type MemoriesFiltersProps<TData> = {
12
+ tabs?: ReactNode;
13
+ kindFilter: KindFilter;
14
+ onKindFilterChange: (kind: KindFilter) => void;
15
+ searchQuery: string;
16
+ onSearchQueryChange: (query: string) => void;
17
+ importanceFilter: ImportanceFilter;
18
+ onImportanceFilterChange: (importance: ImportanceFilter) => void;
19
+ table: Table<TData>;
20
+ columnLabels?: Record<string, string>;
21
+ columnDefaultOrder?: string[];
22
+ schemas?: GQLMemorySchema[];
23
+ schemaFilter?: SchemaFilter;
24
+ onSchemaFilterChange?: (iri: SchemaFilter) => void;
25
+ statusFilters?: Record<StatusFilterKey, boolean>;
26
+ onStatusFilterChange?: (key: StatusFilterKey, value: boolean) => void;
27
+ visibleStatusFilters?: StatusFilterKey[];
28
+ };
29
+ export declare function MemoriesFilters<TData>(props: MemoriesFiltersProps<TData>): import("react/jsx-runtime").JSX.Element;
30
+ export {};
31
+ //# sourceMappingURL=MemoriesFilters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoriesFilters.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/MemoriesFilters.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAuBjF,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,aAAa,CAAC;AAC/C,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AA2BnD,eAAO,MAAM,iBAAiB,EAAE;IAAE,EAAE,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAMhE,CAAC;AAWF,KAAK,oBAAoB,CAAC,KAAK,IAAI;IACjC,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,kBAAkB,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C,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,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IACjD,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtE,oBAAoB,CAAC,EAAE,eAAe,EAAE,CAAC;CAC1C,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,2CAkTxE"}
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { GQLMemoryKind } from "@manta-eu/client";
3
+ import { isPresent } from "@manta-eu/lib/present";
4
+ import { ChevronDown, X } from "lucide-react";
5
+ import { defaultColumnOrder, memoryColumnLabels } from "../hooks/useMemoryColumns.js";
6
+ import { Button } from "#components/button/index";
7
+ import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, ComboboxTrigger, } from "#components/combobox/index";
8
+ import { Dropdown, DropdownCheckboxItem, DropdownContent, DropdownGroup, DropdownItem, DropdownTrigger, } from "#components/dropdown/index";
9
+ import { FilterChip, FilterSection, FilterSheet } from "#components/filter-sheet/index";
10
+ import { Input } from "#components/input/index";
11
+ import { TableColumnRearrangePopover } from "#components/table/index";
12
+ const statusFilterConfig = [
13
+ { key: "autoCaptured", label: "Auto-captured" },
14
+ {
15
+ key: "hideStale",
16
+ label: "Still trusted",
17
+ title: "Within its trust horizon - says nothing about the validity window",
18
+ },
19
+ { key: "promotion", label: "Promotion candidates" },
20
+ { key: "deadWeight", label: "Dead weight", title: "Eligible for pre-loading but nothing has touched it in 90 days" },
21
+ { key: "unused", label: "Never used", title: "Eligible for pre-loading, but the agent has never drawn on it" },
22
+ {
23
+ key: "needsReview",
24
+ label: "Needs review",
25
+ title: "No longer trusted, or about to be - re-confirm it to keep it in context",
26
+ },
27
+ ];
28
+ export const kindFilterOptions = [
29
+ { id: "ALL", label: "All kinds" },
30
+ { id: GQLMemoryKind.Preference, label: "Preference" },
31
+ { id: GQLMemoryKind.Fact, label: "Fact" },
32
+ { id: GQLMemoryKind.Objective, label: "Objective" },
33
+ { id: GQLMemoryKind.Context, label: "Context" },
34
+ ];
35
+ const importanceFilterOptions = [
36
+ { id: 0, label: "All importance" },
37
+ { id: 1, label: "Disabled" },
38
+ { id: 2, label: "Low" },
39
+ { id: 3, label: "Medium" },
40
+ { id: 4, label: "High" },
41
+ { id: 5, label: "Critical" },
42
+ ];
43
+ export function MemoriesFilters(props) {
44
+ const { tabs, kindFilter, onKindFilterChange, searchQuery, onSearchQueryChange, importanceFilter, onImportanceFilterChange, table, columnLabels = memoryColumnLabels, columnDefaultOrder = defaultColumnOrder, schemas, schemaFilter = "ALL", onSchemaFilterChange, statusFilters, onStatusFilterChange, visibleStatusFilters = [], } = props;
45
+ const allKindsSelected = kindFilter === "ALL";
46
+ const allImportancesSelected = importanceFilter === 0;
47
+ const allSchemasSelected = schemaFilter === "ALL";
48
+ const selectedKindLabel = kindFilterOptions.find((o) => o.id === kindFilter)?.label;
49
+ const selectedSchemaLabel = schemaFilter === "NONE" ? "No schema" : schemas?.find((s) => s.iri === schemaFilter)?.label;
50
+ const selectedImportanceOption = importanceFilterOptions.find((o) => o.id === importanceFilter);
51
+ const statusFilterOptions = onStatusFilterChange
52
+ ? statusFilterConfig
53
+ .filter((cfg) => visibleStatusFilters.includes(cfg.key))
54
+ .map((cfg) => ({
55
+ id: cfg.key,
56
+ label: cfg.label,
57
+ active: !!statusFilters?.[cfg.key],
58
+ onChange: (value) => onStatusFilterChange(cfg.key, value),
59
+ ...(cfg.title ? { title: cfg.title } : {}),
60
+ }))
61
+ : [];
62
+ const activeStatusCount = statusFilterOptions.filter((option) => option.active).length;
63
+ const hasActiveFilters = isPresent(searchQuery) ||
64
+ !allKindsSelected ||
65
+ !allImportancesSelected ||
66
+ !allSchemasSelected ||
67
+ activeStatusCount > 0;
68
+ function handleClearFilters() {
69
+ onSearchQueryChange("");
70
+ onKindFilterChange("ALL");
71
+ onImportanceFilterChange(0);
72
+ onSchemaFilterChange?.("ALL");
73
+ for (const option of statusFilterOptions) {
74
+ if (option.active)
75
+ option.onChange(false);
76
+ }
77
+ }
78
+ const activeFilterCount = (isPresent(searchQuery) ? 1 : 0) +
79
+ (allKindsSelected ? 0 : 1) +
80
+ (allImportancesSelected ? 0 : 1) +
81
+ (allSchemasSelected ? 0 : 1) +
82
+ activeStatusCount;
83
+ function filterControls() {
84
+ return (_jsxs(_Fragment, { children: [_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", children: [_jsx("span", { children: allKindsSelected ? "Kind" : selectedKindLabel }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "w-44", children: _jsx(DropdownGroup, { label: "Filter by kind", children: kindFilterOptions.map((option) => (_jsx(DropdownItem, { selected: option.id === kindFilter, onClick: () => onKindFilterChange(option.id), children: option.label }, option.id))) }) })] }), isPresent(schemas) && onSchemaFilterChange && (_jsxs(Combobox, { children: [_jsx(ComboboxTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", children: [_jsx("span", { children: allSchemasSelected ? "Schema" : selectedSchemaLabel }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsxs(ComboboxContent, { align: "start", className: "w-52", children: [_jsx(ComboboxInput, { placeholder: "Search schemas\u2026" }), _jsxs(ComboboxList, { children: [_jsx(ComboboxEmpty, { children: "No schemas found" }), _jsx(ComboboxItem, { value: "All schemas", selected: allSchemasSelected, onSelect: () => onSchemaFilterChange("ALL"), children: "All schemas" }), _jsx(ComboboxItem, { value: "No schema", selected: schemaFilter === "NONE", onSelect: () => onSchemaFilterChange("NONE"), children: "No schema" }), schemas.map((schema) => (_jsx(ComboboxItem, { value: schema.label, selected: schemaFilter === schema.iri, onSelect: () => onSchemaFilterChange(schema.iri), children: schema.label }, schema.iri)))] })] })] })), _jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", children: [_jsx("span", { children: allImportancesSelected ? "Importance" : selectedImportanceOption?.label }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "w-44", children: _jsx(DropdownGroup, { label: "Filter by importance", children: importanceFilterOptions.map((option) => (_jsx(DropdownItem, { selected: option.id === importanceFilter, onClick: () => onImportanceFilterChange(option.id), children: option.label }, option.id))) }) })] }), isPresent(statusFilterOptions) && (_jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: activeStatusCount > 0 ? "secondary" : "tertiary", size: "base", rounded: "lg", children: [_jsx("span", { children: activeStatusCount > 0 ? `Status (${activeStatusCount})` : "Status" }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "w-56", children: _jsx(DropdownGroup, { label: "Filter by status", children: statusFilterOptions.map((option) => (_jsx(DropdownCheckboxItem, { checked: option.active, onCheckedChange: option.onChange, ...(option.title ? { title: option.title } : {}), children: option.label }, option.id))) }) })] })), hasActiveFilters && (_jsx(Button, { variant: "ghost", size: "base", rounded: "lg", onClick: handleClearFilters, icon: X, children: "Clear filters" }))] }));
85
+ }
86
+ const filterSheetContent = (_jsxs(_Fragment, { children: [_jsx(FilterSection, { title: "Kind", children: _jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", className: "w-full justify-between", children: [_jsx("span", { children: selectedKindLabel }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "w-(--radix-dropdown-menu-trigger-width)", children: _jsx(DropdownGroup, { label: "Filter by kind", children: kindFilterOptions.map((option) => (_jsx(DropdownItem, { selected: option.id === kindFilter, onClick: () => onKindFilterChange(option.id), children: option.label }, option.id))) }) })] }) }), isPresent(schemas) && onSchemaFilterChange && (_jsx(FilterSection, { title: "Schema", children: _jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", className: "w-full justify-between", children: [_jsx("span", { children: allSchemasSelected ? "All schemas" : selectedSchemaLabel }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "max-h-64 w-(--radix-dropdown-menu-trigger-width) overflow-y-auto", children: _jsxs(DropdownGroup, { label: "Filter by schema", children: [_jsx(DropdownItem, { selected: allSchemasSelected, onClick: () => onSchemaFilterChange("ALL"), children: "All schemas" }), _jsx(DropdownItem, { selected: schemaFilter === "NONE", onClick: () => onSchemaFilterChange("NONE"), children: "No schema" }), schemas.map((schema) => (_jsx(DropdownItem, { selected: schemaFilter === schema.iri, onClick: () => onSchemaFilterChange(schema.iri), children: schema.label }, schema.iri)))] }) })] }) })), _jsx(FilterSection, { title: "Importance", children: _jsxs(Dropdown, { children: [_jsx(DropdownTrigger, { asChild: true, children: _jsxs(Button, { variant: "tertiary", size: "base", rounded: "lg", className: "w-full justify-between", children: [_jsx("span", { children: selectedImportanceOption?.label }), _jsx(ChevronDown, { className: "size-4" })] }) }), _jsx(DropdownContent, { align: "start", className: "w-(--radix-dropdown-menu-trigger-width)", children: _jsx(DropdownGroup, { label: "Filter by importance", children: importanceFilterOptions.map((option) => (_jsx(DropdownItem, { selected: option.id === importanceFilter, onClick: () => onImportanceFilterChange(option.id), children: option.label }, option.id))) }) })] }) }), isPresent(statusFilterOptions) && (_jsx(FilterSection, { title: "Status", children: statusFilterOptions.map((option) => (_jsx(FilterChip, { selected: option.active, label: option.label, description: option.title, onClick: () => option.onChange(!option.active) }, option.id))) }))] }));
87
+ return (_jsxs("div", { className: "flex min-w-0 flex-col gap-3 3xl:flex-row 3xl:items-center", children: [isPresent(tabs) && _jsx("div", { className: "min-w-0 3xl:shrink", children: tabs }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 flex-1 min-w-0", children: [_jsx(Input, { containerClassName: "min-w-0 flex-1 sm:w-64 sm:flex-none", type: "search", variant: "search", placeholder: "Search memories...", value: searchQuery, onChange: (event) => onSearchQueryChange(event.target.value) }), _jsx("div", { className: "sm:hidden", children: _jsx(FilterSheet, { activeCount: activeFilterCount, onReset: handleClearFilters, children: filterSheetContent }) }), _jsx("div", { className: "hidden sm:contents", children: filterControls() }), _jsx("div", { className: "ml-auto hidden shrink-0 sm:block", children: _jsx(TableColumnRearrangePopover, { enableReset: true, table: table, columnLabels: columnLabels, defaultOrder: columnDefaultOrder }) })] })] }));
88
+ }
@@ -0,0 +1,6 @@
1
+ export type MemoriesPanelProps = {
2
+ isOperator?: boolean;
3
+ onClose: () => void;
4
+ };
5
+ export declare function MemoriesPanel(props: MemoriesPanelProps): import("react/jsx-runtime").JSX.Element;
6
+ //# sourceMappingURL=MemoriesPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoriesPanel.d.ts","sourceRoot":"","sources":["../../../../src/routes/memories/components/MemoriesPanel.tsx"],"names":[],"mappings":"AA4BA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,2CA2KtD"}