@manta-eu/react 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/channel-icon/index.d.ts +1 -0
- package/dist/components/channel-icon/index.d.ts.map +1 -1
- package/dist/components/channel-icon/index.js +1 -1
- package/dist/components/channel-icon/index.js.map +1 -1
- package/dist/components/planning/ActioningView.d.ts +1 -2
- package/dist/components/planning/ActioningView.d.ts.map +1 -1
- package/dist/components/planning/ActioningView.js +19 -44
- package/dist/components/planning/ActioningView.js.map +1 -1
- package/dist/components/planning/ManualActionCard.d.ts +4 -0
- package/dist/components/planning/ManualActionCard.d.ts.map +1 -1
- package/dist/components/planning/ManualActionCard.js +7 -5
- package/dist/components/planning/ManualActionCard.js.map +1 -1
- package/dist/components/planning/ManualActionList.d.ts +4 -0
- package/dist/components/planning/ManualActionList.d.ts.map +1 -1
- package/dist/components/planning/ManualActionList.js +8 -2
- package/dist/components/planning/ManualActionList.js.map +1 -1
- package/dist/components/planning/actioning-view-utils.d.ts +9 -0
- package/dist/components/planning/actioning-view-utils.d.ts.map +1 -1
- package/dist/components/planning/actioning-view-utils.js +19 -1
- package/dist/components/planning/actioning-view-utils.js.map +1 -1
- package/dist/components/tooltip/index.d.ts +7 -0
- package/dist/components/tooltip/index.d.ts.map +1 -1
- package/dist/components/tooltip/index.js +10 -1
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/globals.css +19 -6
- package/dist/graph/entity-link.d.ts +14 -0
- package/dist/graph/entity-link.d.ts.map +1 -0
- package/dist/graph/entity-link.js +12 -0
- package/dist/graph/entity-link.js.map +1 -0
- package/dist/graph/graph-list-utils.d.ts +1 -0
- package/dist/graph/graph-list-utils.d.ts.map +1 -1
- package/dist/graph/graph-list-utils.js +1 -0
- package/dist/graph/graph-list-utils.js.map +1 -1
- package/dist/graph/graph-model.d.ts.map +1 -1
- package/dist/graph/graph-model.js +14 -5
- package/dist/graph/graph-model.js.map +1 -1
- package/dist/graph/nodes/BrandAssetAnalysisView.d.ts.map +1 -1
- package/dist/graph/nodes/BrandAssetAnalysisView.js +2 -1
- package/dist/graph/nodes/BrandAssetAnalysisView.js.map +1 -1
- package/dist/graph/nodes/BrandFontSuggestionView.d.ts.map +1 -1
- package/dist/graph/nodes/BrandFontSuggestionView.js +2 -1
- package/dist/graph/nodes/BrandFontSuggestionView.js.map +1 -1
- package/dist/graph/nodes/BrandGuidelinesView.js +1 -1
- package/dist/graph/nodes/BrandGuidelinesView.js.map +1 -1
- package/dist/graph/nodes/NodePropertyTable.d.ts +4 -2
- package/dist/graph/nodes/NodePropertyTable.d.ts.map +1 -1
- package/dist/graph/nodes/NodePropertyTable.js +12 -59
- package/dist/graph/nodes/NodePropertyTable.js.map +1 -1
- package/dist/graph/nodes/node-property-row.d.ts +30 -0
- package/dist/graph/nodes/node-property-row.d.ts.map +1 -0
- package/dist/graph/nodes/node-property-row.js +35 -0
- package/dist/graph/nodes/node-property-row.js.map +1 -0
- package/dist/graph/property-formatters.d.ts +1 -0
- package/dist/graph/property-formatters.d.ts.map +1 -1
- package/dist/graph/property-formatters.js +4 -1
- package/dist/graph/property-formatters.js.map +1 -1
- package/dist/graph/special-nodes/AttributeList.d.ts +27 -0
- package/dist/graph/special-nodes/AttributeList.d.ts.map +1 -0
- package/dist/graph/special-nodes/AttributeList.js +57 -0
- package/dist/graph/special-nodes/AttributeList.js.map +1 -0
- package/dist/graph/special-nodes/EntityPreview.d.ts +5 -0
- package/dist/graph/special-nodes/EntityPreview.d.ts.map +1 -0
- package/dist/graph/special-nodes/EntityPreview.js +19 -0
- package/dist/graph/special-nodes/EntityPreview.js.map +1 -0
- package/dist/graph/special-nodes/EntityValueChip.d.ts +11 -0
- package/dist/graph/special-nodes/EntityValueChip.d.ts.map +1 -0
- package/dist/graph/special-nodes/EntityValueChip.js +40 -0
- package/dist/graph/special-nodes/EntityValueChip.js.map +1 -0
- package/dist/graph/special-nodes/GenericView.d.ts +2 -1
- package/dist/graph/special-nodes/GenericView.d.ts.map +1 -1
- package/dist/graph/special-nodes/GenericView.js +23 -69
- package/dist/graph/special-nodes/GenericView.js.map +1 -1
- package/dist/graph/special-nodes/card-facts.d.ts +52 -0
- package/dist/graph/special-nodes/card-facts.d.ts.map +1 -0
- package/dist/graph/special-nodes/card-facts.js +189 -0
- package/dist/graph/special-nodes/card-facts.js.map +1 -0
- package/dist/graph/special-nodes/property-icons.d.ts +9 -0
- package/dist/graph/special-nodes/property-icons.d.ts.map +1 -0
- package/dist/graph/special-nodes/property-icons.js +39 -0
- package/dist/graph/special-nodes/property-icons.js.map +1 -0
- package/dist/graph/status-utils.d.ts +16 -0
- package/dist/graph/status-utils.d.ts.map +1 -1
- package/dist/graph/status-utils.js +35 -0
- package/dist/graph/status-utils.js.map +1 -1
- package/dist/graph/types.d.ts +5 -0
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/hooks/use-approve-anyway.d.ts +12 -0
- package/dist/hooks/use-approve-anyway.d.ts.map +1 -0
- package/dist/hooks/use-approve-anyway.js +81 -0
- package/dist/hooks/use-approve-anyway.js.map +1 -0
- package/dist/hooks/use-connection-problems.d.ts.map +1 -1
- package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
- package/dist/ldo-ui.d.ts +2 -1
- package/dist/ldo-ui.d.ts.map +1 -1
- package/dist/ldo-ui.js +1 -0
- package/dist/ldo-ui.js.map +1 -1
- package/dist/lib/manual-actions.d.ts +2 -1
- package/dist/lib/manual-actions.d.ts.map +1 -1
- package/dist/lib/manual-actions.js +3 -2
- package/dist/lib/manual-actions.js.map +1 -1
- package/dist/providers/ActiveChatProvider.js +3 -1
- package/dist/providers/ActiveChatProvider.js.map +1 -1
- package/dist/providers/ChatManagerProvider.d.ts.map +1 -1
- package/dist/providers/ChatManagerProvider.js +3 -1
- package/dist/providers/ChatManagerProvider.js.map +1 -1
- package/dist/providers/chat-socket-auth.d.ts +7 -2
- package/dist/providers/chat-socket-auth.d.ts.map +1 -1
- package/dist/providers/chat-socket-auth.js +87 -16
- package/dist/providers/chat-socket-auth.js.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +8 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/routes/activity/detail/ActivityChanges.d.ts +2 -0
- package/dist/routes/activity/detail/ActivityChanges.d.ts.map +1 -1
- package/dist/routes/activity/detail/ActivityChanges.js +8 -7
- package/dist/routes/activity/detail/ActivityChanges.js.map +1 -1
- package/dist/routes/activity/detail/ActivityDetail.d.ts +1 -0
- package/dist/routes/activity/detail/ActivityDetail.d.ts.map +1 -1
- package/dist/routes/activity/detail/ActivityDetail.js +5 -4
- package/dist/routes/activity/detail/ActivityDetail.js.map +1 -1
- package/dist/routes/activity/detail/ActivityStepsRail.d.ts +1 -0
- package/dist/routes/activity/detail/ActivityStepsRail.d.ts.map +1 -1
- package/dist/routes/activity/detail/ActivityStepsRail.js +3 -2
- package/dist/routes/activity/detail/ActivityStepsRail.js.map +1 -1
- package/dist/routes/activity/detail/ActivityTimeline.js +2 -2
- package/dist/routes/activity/detail/ActivityTimeline.js.map +1 -1
- package/dist/routes/activity/detail/NoChangesMessage.d.ts +6 -0
- package/dist/routes/activity/detail/NoChangesMessage.d.ts.map +1 -0
- package/dist/routes/activity/detail/NoChangesMessage.js +10 -0
- package/dist/routes/activity/detail/NoChangesMessage.js.map +1 -0
- package/dist/routes/data-explorer/components/RawTriples.js +1 -1
- package/dist/routes/data-explorer/components/RawTriples.js.map +1 -1
- package/dist/routes/data-explorer/components/RecentTypes.js +1 -1
- package/dist/routes/data-explorer/components/RecentTypes.js.map +1 -1
- package/dist/routes/data-explorer/components/class-detail/Instances.js +1 -1
- package/dist/routes/data-explorer/components/class-detail/Instances.js.map +1 -1
- package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js +1 -1
- package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js.map +1 -1
- package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js +1 -1
- package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js.map +1 -1
- package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js +1 -1
- package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js.map +1 -1
- package/dist/routes/data-explorer/components/record-detail/ChatPreview.js +2 -2
- package/dist/routes/data-explorer/components/record-detail/ChatPreview.js.map +1 -1
- package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.d.ts.map +1 -1
- package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js +13 -6
- package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js.map +1 -1
- package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts +3 -0
- package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts.map +1 -1
- package/dist/routes/integrations/components/connect-forms/data-connection-fields.js +9 -2
- package/dist/routes/integrations/components/connect-forms/data-connection-fields.js.map +1 -1
- package/dist/routes/plans/components/ActionPlanPage.d.ts.map +1 -1
- package/dist/routes/plans/components/ActionPlanPage.js +4 -7
- package/dist/routes/plans/components/ActionPlanPage.js.map +1 -1
- package/dist/routes/plans/components/PlanDetailRouteContent.d.ts.map +1 -1
- package/dist/routes/plans/components/PlanDetailRouteContent.js +2 -1
- package/dist/routes/plans/components/PlanDetailRouteContent.js.map +1 -1
- package/package.json +12 -7
- package/src/app-subpaths.json +1 -0
- package/src/components/channel-icon/index.tsx +1 -1
- package/src/components/planning/ActioningView.tsx +62 -70
- package/src/components/planning/ManualActionCard.tsx +66 -14
- package/src/components/planning/ManualActionList.tsx +30 -11
- package/src/components/planning/actioning-view-utils.ts +27 -1
- package/src/components/tooltip/index.tsx +35 -2
- package/src/graph/entity-link.tsx +20 -0
- package/src/graph/graph-list-utils.ts +2 -0
- package/src/graph/graph-model.ts +15 -6
- package/src/graph/nodes/BrandAssetAnalysisView.tsx +3 -1
- package/src/graph/nodes/BrandFontSuggestionView.tsx +7 -1
- package/src/graph/nodes/BrandGuidelinesView.tsx +1 -1
- package/src/graph/nodes/NodePropertyTable.tsx +32 -143
- package/src/graph/nodes/node-property-row.tsx +154 -0
- package/src/graph/property-formatters.ts +5 -1
- package/src/graph/special-nodes/AttributeList.tsx +177 -0
- package/src/graph/special-nodes/EntityPreview.tsx +27 -0
- package/src/graph/special-nodes/EntityValueChip.tsx +85 -0
- package/src/graph/special-nodes/GenericView.tsx +49 -139
- package/src/graph/special-nodes/card-facts.ts +278 -0
- package/src/graph/special-nodes/property-icons.ts +59 -0
- package/src/graph/status-utils.ts +40 -0
- package/src/graph/types.ts +4 -0
- package/src/hooks/use-approve-anyway.ts +100 -0
- package/src/ldo-ui.ts +8 -0
- package/src/lib/manual-actions.ts +3 -2
- package/src/providers/ActiveChatProvider.tsx +3 -1
- package/src/providers/ChatManagerProvider.tsx +3 -1
- package/src/providers/chat-socket-auth.ts +95 -16
- package/src/providers/index.tsx +16 -1
- package/src/routes/activity/detail/ActivityChanges.tsx +21 -5
- package/src/routes/activity/detail/ActivityDetail.tsx +24 -5
- package/src/routes/activity/detail/ActivityStepsRail.tsx +4 -2
- package/src/routes/activity/detail/ActivityTimeline.tsx +2 -2
- package/src/routes/activity/detail/NoChangesMessage.tsx +20 -0
- package/src/routes/data-explorer/components/RawTriples.tsx +1 -1
- package/src/routes/data-explorer/components/RecentTypes.tsx +1 -1
- package/src/routes/data-explorer/components/class-detail/Instances.tsx +1 -1
- package/src/routes/data-explorer/components/namespace-detail/NamespaceClassRow.tsx +1 -1
- package/src/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.tsx +1 -1
- package/src/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.tsx +1 -1
- package/src/routes/data-explorer/components/record-detail/ChatPreview.tsx +2 -2
- package/src/routes/integrations/components/connect-forms/DataConnectionConnectForm.tsx +38 -12
- package/src/routes/integrations/components/connect-forms/data-connection-fields.ts +11 -2
- package/src/routes/plans/components/ActionPlanPage.tsx +9 -8
- package/src/routes/plans/components/PlanDetailRouteContent.tsx +4 -3
- package/dist/components/planning/ExecutionActivityRow.d.ts +0 -9
- package/dist/components/planning/ExecutionActivityRow.d.ts.map +0 -1
- package/dist/components/planning/ExecutionActivityRow.js +0 -53
- package/dist/components/planning/ExecutionActivityRow.js.map +0 -1
- package/dist/components/planning/ExecutionSectionItem.d.ts +0 -20
- package/dist/components/planning/ExecutionSectionItem.d.ts.map +0 -1
- package/dist/components/planning/ExecutionSectionItem.js +0 -66
- package/dist/components/planning/ExecutionSectionItem.js.map +0 -1
- package/dist/components/planning/ExecutionSections.d.ts +0 -16
- package/dist/components/planning/ExecutionSections.d.ts.map +0 -1
- package/dist/components/planning/ExecutionSections.js +0 -32
- package/dist/components/planning/ExecutionSections.js.map +0 -1
- package/dist/components/planning/action-plan-icons.d.ts +0 -3
- package/dist/components/planning/action-plan-icons.d.ts.map +0 -1
- package/dist/components/planning/action-plan-icons.js +0 -25
- package/dist/components/planning/action-plan-icons.js.map +0 -1
- package/dist/components/planning/execution-section-model.d.ts +0 -24
- package/dist/components/planning/execution-section-model.d.ts.map +0 -1
- package/dist/components/planning/execution-section-model.js +0 -150
- package/dist/components/planning/execution-section-model.js.map +0 -1
- package/dist/routes/data-explorer/components/TruncateTooltip.d.ts +0 -7
- package/dist/routes/data-explorer/components/TruncateTooltip.d.ts.map +0 -1
- package/dist/routes/data-explorer/components/TruncateTooltip.js +0 -9
- package/dist/routes/data-explorer/components/TruncateTooltip.js.map +0 -1
- package/src/components/planning/ExecutionActivityRow.tsx +0 -89
- package/src/components/planning/ExecutionSectionItem.tsx +0 -184
- package/src/components/planning/ExecutionSections.tsx +0 -97
- package/src/components/planning/action-plan-icons.tsx +0 -27
- package/src/components/planning/execution-section-model.ts +0 -190
- package/src/routes/data-explorer/components/TruncateTooltip.tsx +0 -25
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { isFullIri } from "@manta-eu/client/shared/rdf-namespaces";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { compactUri, expandPrefix } from "@manta-eu/rdf-lib/namespaces";
|
|
4
|
+
import type { LucideIcon } from "lucide-react";
|
|
5
|
+
import { groupBy, isNotNil, uniq } from "ramda";
|
|
6
|
+
import {
|
|
7
|
+
getCurrencyCode,
|
|
8
|
+
isDisplayablePreviewKey,
|
|
9
|
+
normalizePredicateKey,
|
|
10
|
+
selectPriorityPreviewFields,
|
|
11
|
+
type PreviewFieldHints,
|
|
12
|
+
} from "../graph-list-utils";
|
|
13
|
+
import { classifyPropertyDisplay, type PropertyDisplay } from "../nodes/node-property-display";
|
|
14
|
+
import { ontologyPropertyIri } from "../ontology-labels";
|
|
15
|
+
import { formatDisplayValue, isIsoDateTime, parseNumeric } from "../property-formatters";
|
|
16
|
+
import { rdfTypeColors } from "../rdf-type-colors";
|
|
17
|
+
import type { NodeProperty, NodeRelation } from "../types";
|
|
18
|
+
import { getChannelFromId } from "./node-data";
|
|
19
|
+
import { propertyIcon, relationIcon } from "./property-icons";
|
|
20
|
+
import type { Channel } from "#components/channel-icon/index";
|
|
21
|
+
import { formatPropertyLabel } from "#lib/iri-labels";
|
|
22
|
+
import type { OntologyTerm } from "#lib/ontology-terms";
|
|
23
|
+
import { searchItems } from "#lib/search";
|
|
24
|
+
|
|
25
|
+
export const explainCardMaxFacts = 5;
|
|
26
|
+
export const defaultCardMaxFacts = 4;
|
|
27
|
+
export const attributeSearchThreshold = 8;
|
|
28
|
+
export const collapsedChipLimit = 3;
|
|
29
|
+
|
|
30
|
+
const defaultColor = "#6b7280";
|
|
31
|
+
const importantKeys = new Set(["name", "title", "label", "description", "id", "identifier"]);
|
|
32
|
+
|
|
33
|
+
export type CardFact = {
|
|
34
|
+
key: string;
|
|
35
|
+
predicate?: string;
|
|
36
|
+
label: string;
|
|
37
|
+
value: string;
|
|
38
|
+
display: PropertyDisplay;
|
|
39
|
+
icon: LucideIcon;
|
|
40
|
+
entityIris: string[];
|
|
41
|
+
entityColor?: string;
|
|
42
|
+
highlighted: boolean;
|
|
43
|
+
channel?: Channel;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function typeColor(type?: string): string {
|
|
47
|
+
if (!type) return defaultColor;
|
|
48
|
+
return rdfTypeColors[type] ?? rdfTypeColors[expandPrefix(type)] ?? defaultColor;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Only numbers and timestamps are reformatted; text such as "FR" stays as stored.
|
|
52
|
+
export function formatFactValue(property: NodeProperty): string {
|
|
53
|
+
if (parseNumeric(property.value) === null && !isIsoDateTime(property.value)) return property.value;
|
|
54
|
+
|
|
55
|
+
return formatDisplayValue(property.value, {
|
|
56
|
+
predicate: property.iri ?? property.key,
|
|
57
|
+
predicateLabel: property.label ?? property.key,
|
|
58
|
+
valueScale: property.valueScale,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function looksRaw(label: string): boolean {
|
|
63
|
+
return !/\s/.test(label) && (/^[a-z]/.test(label) || /[a-z][A-Z]/.test(label) || /[:/#]/.test(label));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function readableLabel(property: NodeProperty): string {
|
|
67
|
+
const raw = property.label || property.iri || property.key;
|
|
68
|
+
|
|
69
|
+
// Only a raw property name or IRI is re-cased; a real label like "ROAS" stays as written.
|
|
70
|
+
return looksRaw(raw) ? formatPropertyLabel(raw) : raw;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function iriChannel(iri: string | undefined): Channel | undefined {
|
|
74
|
+
return iri ? getChannelFromId(compactUri(iri)) : undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function vocabularyPrefix(iri: string): string | undefined {
|
|
78
|
+
const compact = compactUri(iri);
|
|
79
|
+
return compact === iri ? undefined : /^([A-Za-z][\w-]*):/.exec(compact)?.[1];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// A platform with a logo shows it next to the label; another vocabulary than schema.org or the card's own type
|
|
83
|
+
// keeps its prefix as text.
|
|
84
|
+
export function sourcedLabel(label: string, predicate: string | undefined, type?: string): string {
|
|
85
|
+
if (!predicate || isPresent(iriChannel(predicate))) return label;
|
|
86
|
+
|
|
87
|
+
const prefix = vocabularyPrefix(predicate);
|
|
88
|
+
if (!prefix || prefix === "schema" || (type && prefix === vocabularyPrefix(expandPrefix(type)))) return label;
|
|
89
|
+
|
|
90
|
+
return `${prefix.charAt(0).toUpperCase()}${prefix.slice(1)}:${label}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
type LabelSource = (label: string, predicate: string | undefined) => string;
|
|
94
|
+
|
|
95
|
+
const plainLabel: LabelSource = (label) => label;
|
|
96
|
+
|
|
97
|
+
function termFor(terms: Map<string, OntologyTerm>, predicate: string | undefined): OntologyTerm | undefined {
|
|
98
|
+
const iri = ontologyPropertyIri(predicate);
|
|
99
|
+
return iri ? terms.get(iri) : undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Whole words, so "confidence" or "width" never pass for an "id".
|
|
103
|
+
export function keyWords(key: string): string[] {
|
|
104
|
+
return key
|
|
105
|
+
.split(/[^A-Za-z0-9]+|(?<=[a-z0-9])(?=[A-Z])/)
|
|
106
|
+
.filter(Boolean)
|
|
107
|
+
.map((word) => word.toLowerCase());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function relationFacts(
|
|
111
|
+
relations: NodeRelation[],
|
|
112
|
+
terms: Map<string, OntologyTerm>,
|
|
113
|
+
labelFor: LabelSource = plainLabel,
|
|
114
|
+
): CardFact[] {
|
|
115
|
+
const byPredicate = groupBy(
|
|
116
|
+
(relation: NodeRelation) => relation.predicate,
|
|
117
|
+
relations.filter((relation) => isFullIri(relation.target)),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return Object.entries(byPredicate).map(([predicate, group]) => {
|
|
121
|
+
const targets = uniq((group ?? []).map((relation) => relation.target));
|
|
122
|
+
const term = termFor(terms, predicate);
|
|
123
|
+
const range = term?.rangeIncludes[0];
|
|
124
|
+
const allOntologyTerms = targets.every((target) => isPresent(termFor(terms, target)?.label));
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
key: `${predicate} entities`,
|
|
128
|
+
predicate,
|
|
129
|
+
label: labelFor(readableLabel({ key: predicate, value: "", iri: predicate, label: term?.label }), predicate),
|
|
130
|
+
value: targets.join(", "),
|
|
131
|
+
display: { kind: "text", text: targets.join(", ") },
|
|
132
|
+
icon: allOntologyTerms ? propertyIcon({ range, display: { kind: "text", text: "" } }) : relationIcon(range),
|
|
133
|
+
entityIris: targets,
|
|
134
|
+
entityColor: typeColor(range),
|
|
135
|
+
highlighted: false,
|
|
136
|
+
channel: iriChannel(predicate),
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function propertyFact(
|
|
142
|
+
property: NodeProperty,
|
|
143
|
+
jsonLd: Record<string, unknown>,
|
|
144
|
+
terms: Map<string, OntologyTerm>,
|
|
145
|
+
labelFor: LabelSource,
|
|
146
|
+
) {
|
|
147
|
+
const label = readableLabel(property);
|
|
148
|
+
const value = formatFactValue(property);
|
|
149
|
+
const raw = jsonLd[property.iri ?? ""] ?? property.value;
|
|
150
|
+
const display = classifyPropertyDisplay({ label, formatted: value, raw });
|
|
151
|
+
const range = termFor(terms, property.iri)?.rangeIncludes[0];
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
key: property.iri ?? property.key,
|
|
155
|
+
label: labelFor(label, property.iri),
|
|
156
|
+
value,
|
|
157
|
+
display,
|
|
158
|
+
icon: propertyIcon({ range, display, isDate: isIsoDateTime(property.value) }),
|
|
159
|
+
entityIris: [],
|
|
160
|
+
highlighted: false,
|
|
161
|
+
channel: iriChannel(property.iri),
|
|
162
|
+
} satisfies CardFact;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// graph-model records each IRI value as a relation, rendered as a chip; the property keeps only its other values.
|
|
166
|
+
function withoutRelationValues(
|
|
167
|
+
property: NodeProperty,
|
|
168
|
+
relations: NodeRelation[],
|
|
169
|
+
jsonLd: Record<string, unknown>,
|
|
170
|
+
): NodeProperty[] {
|
|
171
|
+
const targets = new Set(
|
|
172
|
+
relations.filter((relation) => relation.predicate === property.iri).map((relation) => relation.target),
|
|
173
|
+
);
|
|
174
|
+
if (targets.size === 0) return [property];
|
|
175
|
+
|
|
176
|
+
const raw = jsonLd[property.iri ?? ""];
|
|
177
|
+
const values = (Array.isArray(raw) ? raw : [raw]).filter(
|
|
178
|
+
(value): value is string | number | boolean => isNotNil(value) && typeof value !== "object",
|
|
179
|
+
);
|
|
180
|
+
const rest = values.map(String).filter((value) => !targets.has(value));
|
|
181
|
+
|
|
182
|
+
return isPresent(rest) ? [{ ...property, value: rest.join(" | ") }] : [];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type BuildCardFactsArgs = {
|
|
186
|
+
properties: NodeProperty[];
|
|
187
|
+
relations: NodeRelation[];
|
|
188
|
+
jsonLd: Record<string, unknown>;
|
|
189
|
+
terms: Map<string, OntologyTerm>;
|
|
190
|
+
title?: string;
|
|
191
|
+
type?: string;
|
|
192
|
+
// Only the fallback card names a foreign vocabulary; typed cards keep their labels as written.
|
|
193
|
+
prefixLabels?: boolean;
|
|
194
|
+
previewHints?: PreviewFieldHints;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export function buildCardFacts(args: BuildCardFactsArgs): { facts: CardFact[]; previewCount: number } {
|
|
198
|
+
const { relations, jsonLd, terms, title, type, prefixLabels = false, previewHints } = args;
|
|
199
|
+
const labelFor: LabelSource = prefixLabels ? (label, predicate) => sourcedLabel(label, predicate, type) : plainLabel;
|
|
200
|
+
|
|
201
|
+
const properties = args.properties.flatMap((property) => withoutRelationValues(property, relations, jsonLd));
|
|
202
|
+
const linkedFacts = relationFacts(relations, terms, labelFor);
|
|
203
|
+
function notTitle(fact: CardFact) {
|
|
204
|
+
return title === undefined || fact.value !== title;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (previewHints) {
|
|
208
|
+
const displayable = properties
|
|
209
|
+
.filter((property) => isDisplayablePreviewKey(property.key))
|
|
210
|
+
.map((property) => ({ ...property, label: readableLabel(property) }));
|
|
211
|
+
const fields = selectPriorityPreviewFields(displayable, previewHints, getCurrencyCode([], properties), {
|
|
212
|
+
limit: displayable.length,
|
|
213
|
+
keepUnmatched: true,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const explainFacts = fields.map((field): CardFact => {
|
|
217
|
+
const display = classifyPropertyDisplay({ label: field.label, formatted: field.value, raw: field.rawValue });
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
key: field.id,
|
|
221
|
+
label: labelFor(field.label, field.predicate),
|
|
222
|
+
value: field.value,
|
|
223
|
+
display,
|
|
224
|
+
icon: propertyIcon({ display, isDate: isIsoDateTime(field.rawValue ?? "") }),
|
|
225
|
+
entityIris: [],
|
|
226
|
+
highlighted: field.isHighlighted ?? false,
|
|
227
|
+
channel: iriChannel(field.predicate),
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const highlight = previewHints.highlightPredicate
|
|
232
|
+
? normalizePredicateKey(previewHints.highlightPredicate)
|
|
233
|
+
: undefined;
|
|
234
|
+
function isHighlighted(fact: CardFact) {
|
|
235
|
+
return isPresent(highlight) && isPresent(fact.predicate) && normalizePredicateKey(fact.predicate) === highlight;
|
|
236
|
+
}
|
|
237
|
+
const linked = linkedFacts.map((fact) => (isHighlighted(fact) ? { ...fact, highlighted: true } : fact));
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
facts: [
|
|
241
|
+
...linked.filter(isHighlighted),
|
|
242
|
+
...explainFacts,
|
|
243
|
+
...linked.filter((fact) => !isHighlighted(fact)),
|
|
244
|
+
].filter(notTitle),
|
|
245
|
+
previewCount: explainCardMaxFacts,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function isImportant(property: NodeProperty) {
|
|
250
|
+
return keyWords(property.key).some((word) => importantKeys.has(word));
|
|
251
|
+
}
|
|
252
|
+
const important = properties.filter(isImportant).map((property) => propertyFact(property, jsonLd, terms, labelFor));
|
|
253
|
+
const other = properties
|
|
254
|
+
.filter((property) => !isImportant(property))
|
|
255
|
+
.map((property) => propertyFact(property, jsonLd, terms, labelFor));
|
|
256
|
+
|
|
257
|
+
return { facts: [...important, ...linkedFacts, ...other].filter(notTitle), previewCount: defaultCardMaxFacts };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function isAttributeSearchable(expanded: boolean, factCount: number): boolean {
|
|
261
|
+
return expanded && factCount > attributeSearchThreshold;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function visibleChips(iris: string[], expanded: boolean): { shown: string[]; hiddenCount: number } {
|
|
265
|
+
const shown = expanded ? iris : iris.slice(0, collapsedChipLimit);
|
|
266
|
+
|
|
267
|
+
return { shown, hiddenCount: iris.length - shown.length };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// A linked-entity row is found by its label: its value is the targets' IRIs, which say nothing a reader sees.
|
|
271
|
+
export function searchFacts(facts: CardFact[], query: string): CardFact[] {
|
|
272
|
+
const documents = facts.map((fact) => ({
|
|
273
|
+
fact,
|
|
274
|
+
text: isPresent(fact.entityIris) ? fact.label : `${fact.label} ${fact.value}`,
|
|
275
|
+
}));
|
|
276
|
+
|
|
277
|
+
return searchItems(documents, query, { keys: ["text"], threshold: 0.35 }).map((document) => document.fact);
|
|
278
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { RangeKind, rangeKind } from "@manta-eu/ldo/range-kinds";
|
|
2
|
+
import { expandPrefix } from "@manta-eu/rdf-lib/namespaces";
|
|
3
|
+
import {
|
|
4
|
+
AlignLeft,
|
|
5
|
+
Building2,
|
|
6
|
+
Calendar,
|
|
7
|
+
CircleDollarSign,
|
|
8
|
+
Hash,
|
|
9
|
+
Link2,
|
|
10
|
+
type LucideIcon,
|
|
11
|
+
Palette,
|
|
12
|
+
Percent,
|
|
13
|
+
Tags,
|
|
14
|
+
ToggleLeft,
|
|
15
|
+
Type,
|
|
16
|
+
User,
|
|
17
|
+
} from "lucide-react";
|
|
18
|
+
import { match } from "ts-pattern";
|
|
19
|
+
import type { PropertyDisplay } from "../nodes/node-property-display";
|
|
20
|
+
|
|
21
|
+
const kindIcons: Record<RangeKind, LucideIcon> = {
|
|
22
|
+
[RangeKind.Text]: Type,
|
|
23
|
+
[RangeKind.Number]: Hash,
|
|
24
|
+
[RangeKind.Boolean]: ToggleLeft,
|
|
25
|
+
[RangeKind.Date]: Calendar,
|
|
26
|
+
[RangeKind.Url]: Link2,
|
|
27
|
+
[RangeKind.Money]: CircleDollarSign,
|
|
28
|
+
[RangeKind.Person]: User,
|
|
29
|
+
[RangeKind.Organization]: Building2,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function displayIcon(display: PropertyDisplay): LucideIcon {
|
|
33
|
+
return match(display)
|
|
34
|
+
.with({ kind: "number" }, () => Hash)
|
|
35
|
+
.with({ kind: "boolean" }, () => ToggleLeft)
|
|
36
|
+
.with({ kind: "color" }, () => Palette)
|
|
37
|
+
.with({ kind: "ratio" }, () => Percent)
|
|
38
|
+
.with({ kind: "tags" }, () => Tags)
|
|
39
|
+
.with({ kind: "prose" }, () => AlignLeft)
|
|
40
|
+
.with({ kind: "text" }, () => Type)
|
|
41
|
+
.exhaustive();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function propertyIcon(args: { range?: string; display?: PropertyDisplay; isDate?: boolean }): LucideIcon {
|
|
45
|
+
const { range, display, isDate = false } = args;
|
|
46
|
+
|
|
47
|
+
const kind = range ? rangeKind(expandPrefix(range)) : undefined;
|
|
48
|
+
if (kind) return kindIcons[kind];
|
|
49
|
+
|
|
50
|
+
if (isDate) return Calendar;
|
|
51
|
+
|
|
52
|
+
return display ? displayIcon(display) : Type;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function relationIcon(range?: string): LucideIcon {
|
|
56
|
+
const kind = range ? rangeKind(expandPrefix(range)) : undefined;
|
|
57
|
+
|
|
58
|
+
return kind === RangeKind.Person || kind === RangeKind.Organization ? kindIcons[kind] : Link2;
|
|
59
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { NodeProperty } from "./types";
|
|
2
|
+
import type { BadgeVariant } from "#components/badge/index";
|
|
2
3
|
|
|
3
4
|
export function titleCase(s: string): string {
|
|
4
5
|
return s.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
@@ -18,6 +19,45 @@ export const statusColors: Record<string, { bg: string; text: string }> = {
|
|
|
18
19
|
deleted: { bg: "#ef4444", text: "#ffffff" },
|
|
19
20
|
};
|
|
20
21
|
|
|
22
|
+
export enum NodeStatus {
|
|
23
|
+
Active = "active",
|
|
24
|
+
Enabled = "enabled",
|
|
25
|
+
Serving = "serving",
|
|
26
|
+
Paused = "paused",
|
|
27
|
+
Pending = "pending",
|
|
28
|
+
Draft = "draft",
|
|
29
|
+
Archived = "archived",
|
|
30
|
+
Disabled = "disabled",
|
|
31
|
+
Removed = "removed",
|
|
32
|
+
Error = "error",
|
|
33
|
+
Deleted = "deleted",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const knownStatuses: ReadonlySet<string> = new Set(Object.values(NodeStatus));
|
|
37
|
+
|
|
38
|
+
export function isNodeStatus(value: string): value is NodeStatus {
|
|
39
|
+
return knownStatuses.has(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const statusBadgeVariants: Record<NodeStatus, BadgeVariant> = {
|
|
43
|
+
[NodeStatus.Active]: "success",
|
|
44
|
+
[NodeStatus.Serving]: "success",
|
|
45
|
+
[NodeStatus.Enabled]: "copy",
|
|
46
|
+
[NodeStatus.Draft]: "copy",
|
|
47
|
+
[NodeStatus.Paused]: "warning",
|
|
48
|
+
[NodeStatus.Pending]: "warning",
|
|
49
|
+
[NodeStatus.Archived]: "copy",
|
|
50
|
+
[NodeStatus.Disabled]: "copy",
|
|
51
|
+
[NodeStatus.Removed]: "destructive",
|
|
52
|
+
[NodeStatus.Error]: "destructive",
|
|
53
|
+
[NodeStatus.Deleted]: "destructive",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export function statusBadgeVariant(status: string): BadgeVariant {
|
|
57
|
+
const normalized = status.trim().toLowerCase();
|
|
58
|
+
return isNodeStatus(normalized) ? statusBadgeVariants[normalized] : "copy";
|
|
59
|
+
}
|
|
60
|
+
|
|
21
61
|
export function getStatusFromProperties(properties: NodeProperty[]): string | undefined {
|
|
22
62
|
return properties.find((p) => {
|
|
23
63
|
const key = p.key.toLowerCase().trim();
|
package/src/graph/types.ts
CHANGED
|
@@ -10,6 +10,9 @@ export type NodeProperty = {
|
|
|
10
10
|
valueScale?: number;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
+
// A property whose value is another entity in the graph; the canvas draws it as an edge instead.
|
|
14
|
+
export type NodeRelation = { predicate: string; target: string };
|
|
15
|
+
|
|
13
16
|
export type RDFNodeData = {
|
|
14
17
|
label: string;
|
|
15
18
|
type?: string;
|
|
@@ -17,6 +20,7 @@ export type RDFNodeData = {
|
|
|
17
20
|
isHub: boolean;
|
|
18
21
|
jsonLd: Record<string, unknown>;
|
|
19
22
|
properties: NodeProperty[];
|
|
23
|
+
relations?: NodeRelation[];
|
|
20
24
|
childIds: string[];
|
|
21
25
|
parentId?: string;
|
|
22
26
|
isCollapsed: boolean;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useExecuteAgentActionAdditionMutation } from "@manta-eu/client";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { isValidFullIri, namespaces } from "@manta-eu/rdf-lib/namespaces";
|
|
4
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
5
|
+
import { DataFactory } from "ldkit/rdf";
|
|
6
|
+
import { sparql } from "ldkit/sparql";
|
|
7
|
+
import { useCallback, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { toast } from "sonner";
|
|
9
|
+
import type { ManualAction } from "./use-manual-actions";
|
|
10
|
+
import { useSparqlSelect } from "./use-sparql-construct";
|
|
11
|
+
import { buildActionDocument, mintSubjectIri } from "#lib/action-document";
|
|
12
|
+
import { useMantaClient } from "#providers/MantaClientProvider";
|
|
13
|
+
import { invalidateActionPlanQueries } from "#shared/query-keys";
|
|
14
|
+
|
|
15
|
+
const df = new DataFactory();
|
|
16
|
+
const assetAnalysis = `${namespaces.brand}AssetAnalysis`;
|
|
17
|
+
const assetDecision = `${namespaces.brand}AssetDecision`;
|
|
18
|
+
const decideAssetShape = `${namespaces.brand}DecideAssetShape`;
|
|
19
|
+
|
|
20
|
+
export type ApproveAnywayHandle = {
|
|
21
|
+
/** Sends the approval; `reviewKey` names the review it answers, so a later review of the same analysis asks again. */
|
|
22
|
+
approve: (analysisIri: string, reviewKey: string) => void;
|
|
23
|
+
approving: ReadonlySet<string>;
|
|
24
|
+
approved: ReadonlySet<string>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Maps each manual action about a brand analysis to that analysis, the one a person can approve anyway. */
|
|
28
|
+
export function useApprovableAnalyses(actions: readonly ManualAction[]): Map<string, string> {
|
|
29
|
+
const aboutIris = useMemo(() => {
|
|
30
|
+
const iris = actions.flatMap(({ aboutIri }) => (isPresent(aboutIri) && isValidFullIri(aboutIri) ? [aboutIri] : []));
|
|
31
|
+
return [...new Set(iris)].sort();
|
|
32
|
+
}, [actions]);
|
|
33
|
+
|
|
34
|
+
const values = aboutIris.map((iri) => sparql`${df.namedNode(iri)}`).join(" ");
|
|
35
|
+
const query = isPresent(aboutIris)
|
|
36
|
+
? `SELECT ?about WHERE { VALUES ?about { ${values} } ?about a ${sparql`${df.namedNode(assetAnalysis)}`} . }`
|
|
37
|
+
: "";
|
|
38
|
+
|
|
39
|
+
const { data } = useSparqlSelect({
|
|
40
|
+
query,
|
|
41
|
+
queryKey: ["ldo-ui", "approvable-analyses", aboutIris],
|
|
42
|
+
enabled: isPresent(aboutIris),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return useMemo(() => {
|
|
46
|
+
const analyses = new Set((data ?? []).flatMap((row) => row.get("about")?.value ?? []));
|
|
47
|
+
const approvable = new Map<string, string>();
|
|
48
|
+
for (const action of actions) {
|
|
49
|
+
if (isPresent(action.aboutIri) && analyses.has(action.aboutIri)) {
|
|
50
|
+
approvable.set(action.subjectIri, action.aboutIri);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return approvable;
|
|
54
|
+
}, [actions, data]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Records a person's approval of an analysis that was not confirmed on-brand, so the rules publish it anyway. */
|
|
58
|
+
export function useApproveAnyway(planGraphIri: string): ApproveAnywayHandle {
|
|
59
|
+
const queryClient = useQueryClient();
|
|
60
|
+
const { mantaClient } = useMantaClient();
|
|
61
|
+
const { mutateAsync: startAddition } = useExecuteAgentActionAdditionMutation(mantaClient);
|
|
62
|
+
const inFlight = useRef(new Set<string>());
|
|
63
|
+
const [approving, setApproving] = useState<ReadonlySet<string>>(() => new Set());
|
|
64
|
+
const [approved, setApproved] = useState<ReadonlySet<string>>(() => new Set());
|
|
65
|
+
|
|
66
|
+
const approve = useCallback(
|
|
67
|
+
(analysisIri: string, reviewKey: string) => {
|
|
68
|
+
if (inFlight.current.has(analysisIri)) return;
|
|
69
|
+
inFlight.current.add(analysisIri);
|
|
70
|
+
setApproving(new Set(inFlight.current));
|
|
71
|
+
const subjectIri = mintSubjectIri(assetDecision);
|
|
72
|
+
const properties = buildActionDocument(
|
|
73
|
+
{ subjectIri, rdfType: assetDecision },
|
|
74
|
+
{
|
|
75
|
+
[`${namespaces.brand}decisionOnAsset`]: { "@id": analysisIri },
|
|
76
|
+
[`${namespaces.brand}decision`]: "approved",
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
void startAddition({
|
|
80
|
+
input: { subjectIri, rdfType: assetDecision, actionShape: decideAssetShape, properties },
|
|
81
|
+
})
|
|
82
|
+
.then(({ executeActionAddition }) => {
|
|
83
|
+
if (!executeActionAddition.success) throw new Error(executeActionAddition.error ?? "The approval failed");
|
|
84
|
+
setApproved((previous) => new Set(previous).add(reviewKey));
|
|
85
|
+
toast.success("Approved. It is uploaded, and this review closes, when the plan next runs.");
|
|
86
|
+
void invalidateActionPlanQueries(queryClient, planGraphIri);
|
|
87
|
+
})
|
|
88
|
+
.catch((error: unknown) => {
|
|
89
|
+
toast.error(error instanceof Error ? error.message : "The approval failed");
|
|
90
|
+
})
|
|
91
|
+
.finally(() => {
|
|
92
|
+
inFlight.current.delete(analysisIri);
|
|
93
|
+
setApproving(new Set(inFlight.current));
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
[startAddition, queryClient, planGraphIri],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return { approve, approving, approved };
|
|
100
|
+
}
|
package/src/ldo-ui.ts
CHANGED
|
@@ -268,6 +268,7 @@ export type {
|
|
|
268
268
|
EntityView,
|
|
269
269
|
EntityViewProps,
|
|
270
270
|
LayoutDirection,
|
|
271
|
+
NodeRelation,
|
|
271
272
|
OnNodeContextMenu,
|
|
272
273
|
RDFNode,
|
|
273
274
|
RDFNodeData,
|
|
@@ -275,6 +276,13 @@ export type {
|
|
|
275
276
|
SampleInstance,
|
|
276
277
|
} from "./graph/types";
|
|
277
278
|
export { jsonLdToRdfGraph } from "./graph/jsonld-bridge";
|
|
279
|
+
export {
|
|
280
|
+
EntityLinkProvider,
|
|
281
|
+
useEntityLink,
|
|
282
|
+
type EntityLinkComponent,
|
|
283
|
+
type EntityLinkProps,
|
|
284
|
+
type EntityLinkProviderProps,
|
|
285
|
+
} from "./graph/entity-link";
|
|
278
286
|
export { rdfGraphToNodesAndEdges, rdfGraphToSummaryNodesAndEdges } from "./graph/graph-model";
|
|
279
287
|
export {
|
|
280
288
|
applyDagreLayout,
|
|
@@ -16,6 +16,7 @@ export function getPendingManualActions(actions: readonly ManualAction[] | undef
|
|
|
16
16
|
return (actions ?? []).filter(isPendingManualAction);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
/** Names the review an approval answers: the step, as of the analysis it currently reports. */
|
|
20
|
+
export function approvalReviewKey(action: Pick<ManualAction, "subjectIri" | "observedValue">): string {
|
|
21
|
+
return `${action.subjectIri}|${action.observedValue ?? ""}`;
|
|
21
22
|
}
|
|
@@ -109,7 +109,9 @@ function ThinkChatSession(props: ThinkChatSessionProps) {
|
|
|
109
109
|
sub: [{ agent: "ThinkChat", name: conversationId }],
|
|
110
110
|
host,
|
|
111
111
|
query: socketAuth.query,
|
|
112
|
-
...("
|
|
112
|
+
...("enabled" in socketAuth
|
|
113
|
+
? { enabled: socketAuth.enabled, shouldReconnectOnClose: socketAuth.shouldReconnectOnClose }
|
|
114
|
+
: {}),
|
|
113
115
|
onClose: handleAgentClose,
|
|
114
116
|
onMessage: handleAgentMessage,
|
|
115
117
|
});
|
|
@@ -97,7 +97,9 @@ export function ChatManagerProvider(props: ChatManagerProviderProps) {
|
|
|
97
97
|
basePath: chatManagerBasePath,
|
|
98
98
|
host: mantaBaseUrl.host,
|
|
99
99
|
query: socketAuth.query,
|
|
100
|
-
...("
|
|
100
|
+
...("enabled" in socketAuth
|
|
101
|
+
? { enabled: socketAuth.enabled, shouldReconnectOnClose: socketAuth.shouldReconnectOnClose }
|
|
102
|
+
: {}),
|
|
101
103
|
});
|
|
102
104
|
|
|
103
105
|
const listConversations = useCallback(
|