@manta-eu/react 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/components/chat-view/Chat.d.ts +20 -0
- package/dist/components/chat-view/Chat.d.ts.map +1 -1
- package/dist/components/chat-view/Chat.js +51 -15
- package/dist/components/chat-view/Chat.js.map +1 -1
- package/dist/components/embedded-chat/index.d.ts +1 -1
- package/dist/components/embedded-chat/index.d.ts.map +1 -1
- package/dist/components/embedded-chat/index.js +1 -1
- package/dist/components/embedded-chat/index.js.map +1 -1
- package/dist/components/planning/ActioningView.d.ts.map +1 -1
- package/dist/components/planning/ActioningView.js +1 -1
- package/dist/components/planning/ActioningView.js.map +1 -1
- package/dist/components/planning/ExecutionTopBar.d.ts +1 -0
- package/dist/components/planning/ExecutionTopBar.d.ts.map +1 -1
- package/dist/components/planning/ExecutionTopBar.js +3 -2
- package/dist/components/planning/ExecutionTopBar.js.map +1 -1
- package/dist/components/planning/plan-detail-utils.d.ts +1 -0
- package/dist/components/planning/plan-detail-utils.d.ts.map +1 -1
- package/dist/components/planning/plan-detail-utils.js +7 -2
- package/dist/components/planning/plan-detail-utils.js.map +1 -1
- package/dist/components/tool-invocation-card/ToolOutputRenderer.d.ts.map +1 -1
- package/dist/components/tool-invocation-card/ToolOutputRenderer.js +5 -2
- package/dist/components/tool-invocation-card/ToolOutputRenderer.js.map +1 -1
- package/dist/graph/EntityCard.d.ts.map +1 -1
- package/dist/graph/EntityCard.js +2 -1
- package/dist/graph/EntityCard.js.map +1 -1
- package/dist/graph/EntityViewWithLinks.d.ts +7 -0
- package/dist/graph/EntityViewWithLinks.d.ts.map +1 -0
- package/dist/graph/EntityViewWithLinks.js +28 -0
- package/dist/graph/EntityViewWithLinks.js.map +1 -0
- package/dist/graph/card-links.d.ts +19 -0
- package/dist/graph/card-links.d.ts.map +1 -0
- package/dist/graph/card-links.js +23 -0
- package/dist/graph/card-links.js.map +1 -0
- package/dist/graph/nodes/BrandAssetAnalysisView.d.ts.map +1 -1
- package/dist/graph/nodes/BrandAssetAnalysisView.js +1 -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 +1 -1
- package/dist/graph/nodes/BrandFontSuggestionView.js.map +1 -1
- package/dist/graph/nodes/EntityCardShell.d.ts +2 -0
- package/dist/graph/nodes/EntityCardShell.d.ts.map +1 -1
- package/dist/graph/nodes/EntityCardShell.js +13 -3
- package/dist/graph/nodes/EntityCardShell.js.map +1 -1
- package/dist/graph/nodes/NodePropertyTable.d.ts +2 -1
- package/dist/graph/nodes/NodePropertyTable.d.ts.map +1 -1
- package/dist/graph/nodes/NodePropertyTable.js +10 -1
- package/dist/graph/nodes/NodePropertyTable.js.map +1 -1
- package/dist/graph/nodes/node-property-display.d.ts +0 -1
- package/dist/graph/nodes/node-property-display.d.ts.map +1 -1
- package/dist/graph/nodes/node-property-display.js +2 -6
- package/dist/graph/nodes/node-property-display.js.map +1 -1
- package/dist/graph/special-nodes/AttributeList.d.ts.map +1 -1
- package/dist/graph/special-nodes/AttributeList.js +3 -2
- package/dist/graph/special-nodes/AttributeList.js.map +1 -1
- package/dist/graph/special-nodes/RelatedSection.d.ts +6 -0
- package/dist/graph/special-nodes/RelatedSection.d.ts.map +1 -0
- package/dist/graph/special-nodes/RelatedSection.js +16 -0
- package/dist/graph/special-nodes/RelatedSection.js.map +1 -0
- package/dist/graph/special-nodes/card-facts.d.ts +2 -0
- package/dist/graph/special-nodes/card-facts.d.ts.map +1 -1
- package/dist/graph/special-nodes/card-facts.js +11 -0
- package/dist/graph/special-nodes/card-facts.js.map +1 -1
- package/dist/graph/types.d.ts +2 -2
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/hooks/use-approve-anyway.d.ts.map +1 -1
- package/dist/hooks/use-approve-anyway.js +8 -8
- package/dist/hooks/use-approve-anyway.js.map +1 -1
- 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 +1 -0
- 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/chat-types.d.ts +17 -0
- package/dist/lib/chat-types.d.ts.map +1 -1
- package/dist/lib/chat-types.js.map +1 -1
- package/dist/providers/ChatManagerProvider.d.ts +7 -0
- package/dist/providers/ChatManagerProvider.d.ts.map +1 -1
- package/dist/providers/ChatManagerProvider.js +129 -16
- package/dist/providers/ChatManagerProvider.js.map +1 -1
- package/dist/providers/chat-connection-context.d.ts +4 -1
- package/dist/providers/chat-connection-context.d.ts.map +1 -1
- package/dist/providers/chat-connection-context.js.map +1 -1
- package/dist/providers/chat-connection-lifecycle.d.ts +1 -0
- package/dist/providers/chat-connection-lifecycle.d.ts.map +1 -1
- package/dist/providers/chat-connection-lifecycle.js.map +1 -1
- package/dist/providers/chat-socket-auth.d.ts +3 -1
- package/dist/providers/chat-socket-auth.d.ts.map +1 -1
- package/dist/providers/chat-socket-auth.js +27 -9
- package/dist/providers/chat-socket-auth.js.map +1 -1
- package/dist/providers/chat-startup-timing.d.ts +14 -0
- package/dist/providers/chat-startup-timing.d.ts.map +1 -0
- package/dist/providers/chat-startup-timing.js +72 -0
- package/dist/providers/chat-startup-timing.js.map +1 -0
- package/dist/routes/data-explorer/components/record-detail/ActionFormDialog.d.ts.map +1 -1
- package/dist/routes/data-explorer/components/record-detail/ActionFormDialog.js +7 -21
- package/dist/routes/data-explorer/components/record-detail/ActionFormDialog.js.map +1 -1
- package/dist/routes/data-explorer/components/record-detail/ChatPreview.d.ts.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/data-explorer/components/record-detail/action-properties.d.ts +2 -2
- package/dist/routes/data-explorer/components/record-detail/action-properties.d.ts.map +1 -1
- package/dist/routes/data-explorer/components/record-detail/action-properties.js +3 -3
- package/dist/routes/data-explorer/components/record-detail/action-properties.js.map +1 -1
- package/dist/routes/integrations/catalog-shape.d.ts +1 -0
- package/dist/routes/integrations/catalog-shape.d.ts.map +1 -1
- package/dist/routes/integrations/catalog-shape.js.map +1 -1
- package/dist/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.d.ts +7 -0
- package/dist/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.d.ts.map +1 -0
- package/dist/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.js +76 -0
- package/dist/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.js.map +1 -0
- package/dist/routes/integrations/components/connect-forms/OAuthSetupConnectForm.d.ts +7 -0
- package/dist/routes/integrations/components/connect-forms/OAuthSetupConnectForm.d.ts.map +1 -1
- package/dist/routes/integrations/components/connect-forms/OAuthSetupConnectForm.js +8 -7
- package/dist/routes/integrations/components/connect-forms/OAuthSetupConnectForm.js.map +1 -1
- package/dist/routes/integrations/components/connect-forms/inferal-locations.d.ts +3 -0
- package/dist/routes/integrations/components/connect-forms/inferal-locations.d.ts.map +1 -0
- package/dist/routes/integrations/components/connect-forms/inferal-locations.js +13 -0
- package/dist/routes/integrations/components/connect-forms/inferal-locations.js.map +1 -0
- package/dist/routes/integrations/connect-forms.d.ts +2 -0
- package/dist/routes/integrations/connect-forms.d.ts.map +1 -1
- package/dist/routes/integrations/connect-forms.js +2 -0
- package/dist/routes/integrations/connect-forms.js.map +1 -1
- package/dist/routes/integrations/connection-view.d.ts.map +1 -1
- package/dist/routes/integrations/connection-view.js +1 -0
- package/dist/routes/integrations/connection-view.js.map +1 -1
- package/dist/routes/plans/components/ActionPlansTableColumns.d.ts.map +1 -1
- package/dist/routes/plans/components/ActionPlansTableColumns.js +3 -3
- package/dist/routes/plans/components/ActionPlansTableColumns.js.map +1 -1
- package/package.json +7 -7
- package/src/components/chat-view/Chat.tsx +62 -15
- package/src/components/embedded-chat/index.tsx +9 -2
- package/src/components/planning/ActioningView.tsx +1 -0
- package/src/components/planning/ExecutionTopBar.tsx +14 -2
- package/src/components/planning/plan-detail-utils.tsx +8 -2
- package/src/components/tool-invocation-card/ToolOutputRenderer.tsx +5 -2
- package/src/graph/EntityCard.tsx +2 -1
- package/src/graph/EntityViewWithLinks.tsx +43 -0
- package/src/graph/card-links.tsx +43 -0
- package/src/graph/nodes/BrandAssetAnalysisView.tsx +1 -0
- package/src/graph/nodes/BrandFontSuggestionView.tsx +1 -0
- package/src/graph/nodes/EntityCardShell.tsx +37 -3
- package/src/graph/nodes/NodePropertyTable.tsx +16 -2
- package/src/graph/nodes/node-property-display.ts +2 -7
- package/src/graph/special-nodes/AttributeList.tsx +4 -2
- package/src/graph/special-nodes/RelatedSection.tsx +29 -0
- package/src/graph/special-nodes/card-facts.ts +13 -0
- package/src/graph/types.ts +1 -1
- package/src/hooks/use-approve-anyway.ts +8 -11
- package/src/ldo-ui.ts +1 -0
- package/src/lib/chat-types.ts +18 -0
- package/src/providers/ChatManagerProvider.tsx +166 -15
- package/src/providers/chat-connection-context.ts +4 -0
- package/src/providers/chat-connection-lifecycle.ts +1 -0
- package/src/providers/chat-socket-auth.ts +31 -12
- package/src/providers/chat-startup-timing.ts +89 -0
- package/src/routes/data-explorer/components/record-detail/ActionFormDialog.tsx +7 -29
- package/src/routes/data-explorer/components/record-detail/ChatPreview.tsx +6 -1
- package/src/routes/data-explorer/components/record-detail/action-properties.ts +3 -3
- package/src/routes/integrations/catalog-shape.ts +2 -0
- package/src/routes/integrations/components/connect-forms/MicrosoftAdsConnectForm.tsx +140 -0
- package/src/routes/integrations/components/connect-forms/OAuthSetupConnectForm.tsx +27 -5
- package/src/routes/integrations/components/connect-forms/inferal-locations.ts +13 -0
- package/src/routes/integrations/connect-forms.ts +2 -0
- package/src/routes/integrations/connection-view.ts +1 -0
- package/src/routes/plans/components/ActionPlansTableColumns.tsx +3 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withChatModeQueryParam } from "@manta-eu/client/shared/chat-manager";
|
|
1
2
|
import { withDatastoreQueryParam } from "@manta-eu/client/shared/datastore-path";
|
|
2
3
|
import { isShowEntitiesResult } from "@manta-eu/client/shared/tools";
|
|
3
4
|
import {
|
|
@@ -5,7 +6,7 @@ import {
|
|
|
5
6
|
type WorkspaceArtifact,
|
|
6
7
|
} from "@manta-eu/client/shared/workspace-artifacts";
|
|
7
8
|
import type { ToolUIPart } from "ai";
|
|
8
|
-
import { useCallback } from "react";
|
|
9
|
+
import { useCallback, useContext } from "react";
|
|
9
10
|
import { match } from "ts-pattern";
|
|
10
11
|
import { FileMessagePart } from "../chat-view/FileMessagePart";
|
|
11
12
|
import { ActionPlanShowcaseCard } from "./ActionPlanShowcaseCard";
|
|
@@ -45,6 +46,7 @@ import {
|
|
|
45
46
|
} from "#components/chart/index";
|
|
46
47
|
import { decodeChartEntities } from "#lib/decode-chart-entities";
|
|
47
48
|
import { cn } from "#lib/utils";
|
|
49
|
+
import { ChatManagerContext } from "#providers/chat-connection-context";
|
|
48
50
|
import { useChatManagerConnection } from "#providers/ChatManagerProvider";
|
|
49
51
|
import { useMantaClient } from "#providers/MantaClientProvider";
|
|
50
52
|
|
|
@@ -129,12 +131,13 @@ function WorkspaceArtifactResultDisplay(props: WorkspaceArtifactResultDisplayPro
|
|
|
129
131
|
const { result } = props;
|
|
130
132
|
|
|
131
133
|
const { datastoreId } = useMantaClient();
|
|
134
|
+
const mode = useContext(ChatManagerContext)?.managerConnection.mode;
|
|
132
135
|
|
|
133
136
|
return (
|
|
134
137
|
<FileMessagePart
|
|
135
138
|
part={{
|
|
136
139
|
type: "file",
|
|
137
|
-
url: withDatastoreQueryParam(result.url, datastoreId),
|
|
140
|
+
url: withChatModeQueryParam(withDatastoreQueryParam(result.url, datastoreId), mode),
|
|
138
141
|
mediaType: result.mediaType,
|
|
139
142
|
filename: result.filename,
|
|
140
143
|
}}
|
package/src/graph/EntityCard.tsx
CHANGED
|
@@ -3,6 +3,7 @@ import { type JsonLdGraphDocument } from "@manta-eu/rdf-lib/jsonld";
|
|
|
3
3
|
import { expandPrefix } from "@manta-eu/rdf-lib/namespaces";
|
|
4
4
|
import { useMemo } from "react";
|
|
5
5
|
import { findDetailViewForTypes } from "./detail-views";
|
|
6
|
+
import { EntityViewWithLinks } from "./EntityViewWithLinks";
|
|
6
7
|
import { rdfGraphToNodesAndEdges } from "./graph-model";
|
|
7
8
|
import { jsonLdToRdfGraph } from "./jsonld-bridge";
|
|
8
9
|
import { GenericView, getEntityView } from "./special-nodes";
|
|
@@ -35,7 +36,7 @@ export function EntityCard(props: EntityCardProps) {
|
|
|
35
36
|
|
|
36
37
|
const View = node ? getEntityView(node.data.type, node.data.actionShape) : undefined;
|
|
37
38
|
|
|
38
|
-
if (node && View) return <View data={node.data} />;
|
|
39
|
+
if (node && View) return <EntityViewWithLinks view={View} data={node.data} />;
|
|
39
40
|
|
|
40
41
|
return <GenericView data={node?.data ?? stubNodeData(entityIri)} />;
|
|
41
42
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
+
import { uniq } from "ramda";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { type CardLinks, CardLinksProvider } from "./card-links";
|
|
5
|
+
import { shouldHidePreviewField } from "./graph-list-utils";
|
|
6
|
+
import { namedRelations } from "./special-nodes/card-facts";
|
|
7
|
+
import type { EntityView, NodeRelation, RDFNodeData } from "./types";
|
|
8
|
+
import { useInstanceLabels } from "#hooks/use-instance-labels";
|
|
9
|
+
|
|
10
|
+
export type EntityViewWithLinksProps = { view: EntityView; data: RDFNodeData };
|
|
11
|
+
|
|
12
|
+
const noRelations: NodeRelation[] = [];
|
|
13
|
+
|
|
14
|
+
function relationKey(relation: NodeRelation): string {
|
|
15
|
+
return `${relation.predicate} ${relation.target}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// The named records a typed card links to go at the top of its frame.
|
|
19
|
+
export function EntityViewWithLinks(props: EntityViewWithLinksProps) {
|
|
20
|
+
const { view: View, data } = props;
|
|
21
|
+
|
|
22
|
+
const relations = useMemo(
|
|
23
|
+
() => (data.relations ?? noRelations).filter((relation) => !shouldHidePreviewField("", relation.predicate)),
|
|
24
|
+
[data.relations],
|
|
25
|
+
);
|
|
26
|
+
const targets = useMemo(() => uniq(relations.map((relation) => relation.target)), [relations]);
|
|
27
|
+
const instanceLabels = useInstanceLabels(targets);
|
|
28
|
+
|
|
29
|
+
// Keyed on which links are named, so a card does not rebuild each time another card's names load.
|
|
30
|
+
const namedKey = namedRelations(relations, instanceLabels).map(relationKey).join("\n");
|
|
31
|
+
|
|
32
|
+
const links = useMemo((): CardLinks | null => {
|
|
33
|
+
const namedKeys = new Set(namedKey.split("\n"));
|
|
34
|
+
const named = relations.filter((relation) => namedKeys.has(relationKey(relation)));
|
|
35
|
+
return isPresent(named) ? { relations: named } : null;
|
|
36
|
+
}, [relations, namedKey]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<CardLinksProvider links={links}>
|
|
40
|
+
<View data={data} />
|
|
41
|
+
</CardLinksProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { IRI } from "@manta-eu/rdf-lib/namespaces";
|
|
2
|
+
import { createContext, type ReactNode, useContext } from "react";
|
|
3
|
+
import type { NodeRelation } from "./types";
|
|
4
|
+
|
|
5
|
+
// The named records a card links to, for the card to list at the top of its frame.
|
|
6
|
+
export type CardLinks = { relations: NodeRelation[] };
|
|
7
|
+
|
|
8
|
+
// A surface such as chat hands the card the records it links to; the canvas sets none.
|
|
9
|
+
const CardLinksContext = createContext<CardLinks | null>(null);
|
|
10
|
+
|
|
11
|
+
const noRecords: ReadonlySet<IRI> = new Set();
|
|
12
|
+
|
|
13
|
+
// The records the card already shows above its content, so a property table leaves them out.
|
|
14
|
+
const LinksShownAboveContext = createContext(noRecords);
|
|
15
|
+
|
|
16
|
+
export type CardLinksProviderProps = { links: CardLinks | null; children: ReactNode };
|
|
17
|
+
|
|
18
|
+
export function CardLinksProvider(props: CardLinksProviderProps) {
|
|
19
|
+
const { links, children } = props;
|
|
20
|
+
|
|
21
|
+
return <CardLinksContext.Provider value={links}>{children}</CardLinksContext.Provider>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useCardLinks(): CardLinks | null {
|
|
25
|
+
return useContext(CardLinksContext);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type CardContentProviderProps = { shown: ReadonlySet<IRI>; children: ReactNode };
|
|
29
|
+
|
|
30
|
+
// Wraps a card's own content: nested cards get no links of their own, and tables learn what is shown above.
|
|
31
|
+
export function CardContentProvider(props: CardContentProviderProps) {
|
|
32
|
+
const { shown, children } = props;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<CardLinksContext.Provider value={null}>
|
|
36
|
+
<LinksShownAboveContext.Provider value={shown}>{children}</LinksShownAboveContext.Provider>
|
|
37
|
+
</CardLinksContext.Provider>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useLinksShownAbove(): ReadonlySet<IRI> {
|
|
42
|
+
return useContext(LinksShownAboveContext);
|
|
43
|
+
}
|
|
@@ -32,6 +32,7 @@ export const BrandAssetAnalysisView = memo(function BrandAssetAnalysisView(props
|
|
|
32
32
|
icon={ScanEye}
|
|
33
33
|
label={`Asset Analysis: ${displayName}`}
|
|
34
34
|
labelMaxWidth="max-w-140"
|
|
35
|
+
omitPredicates={listedElsewhere}
|
|
35
36
|
selected={selected}
|
|
36
37
|
ringColor={ringColor}
|
|
37
38
|
onContextMenu={onContextMenu}
|
|
@@ -101,6 +101,7 @@ export const BrandFontSuggestionView = memo(function BrandFontSuggestionView(pro
|
|
|
101
101
|
icon={Type}
|
|
102
102
|
label={`Font Suggestion: ${family}`}
|
|
103
103
|
labelMaxWidth="max-w-140"
|
|
104
|
+
omitPredicates={listedElsewhere}
|
|
104
105
|
selected={selected}
|
|
105
106
|
ringColor={ringColor}
|
|
106
107
|
onContextMenu={onContextMenu}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
+
import type { IRI } from "@manta-eu/rdf-lib/namespaces";
|
|
1
3
|
import type { LucideIcon } from "lucide-react";
|
|
2
|
-
import { memo, type MouseEvent, type ReactNode } from "react";
|
|
4
|
+
import { memo, type MouseEvent, type ReactNode, useMemo } from "react";
|
|
5
|
+
import { CardContentProvider, useCardLinks } from "../card-links";
|
|
6
|
+
import { RelatedSection } from "../special-nodes/RelatedSection";
|
|
7
|
+
import type { NodeRelation } from "../types";
|
|
3
8
|
import { cn } from "#style";
|
|
4
9
|
|
|
5
10
|
export type EntityCardShellProps = {
|
|
@@ -9,11 +14,31 @@ export type EntityCardShellProps = {
|
|
|
9
14
|
selected?: boolean;
|
|
10
15
|
ringColor?: string;
|
|
11
16
|
onContextMenu?: (e: MouseEvent) => void;
|
|
17
|
+
// Fields the card body shows itself (an image, a weights list), so the links section leaves them out too.
|
|
18
|
+
omitPredicates?: readonly IRI[];
|
|
12
19
|
children: ReactNode;
|
|
13
20
|
};
|
|
14
21
|
|
|
22
|
+
const noRelations: NodeRelation[] = [];
|
|
23
|
+
|
|
15
24
|
export const EntityCardShell = memo(function EntityCardShell(props: EntityCardShellProps) {
|
|
16
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
icon: Icon,
|
|
27
|
+
label,
|
|
28
|
+
labelMaxWidth = "max-w-50",
|
|
29
|
+
selected = false,
|
|
30
|
+
ringColor,
|
|
31
|
+
onContextMenu,
|
|
32
|
+
omitPredicates,
|
|
33
|
+
children,
|
|
34
|
+
} = props;
|
|
35
|
+
const links = useCardLinks();
|
|
36
|
+
|
|
37
|
+
const listed = useMemo(() => {
|
|
38
|
+
const omitted = new Set(omitPredicates);
|
|
39
|
+
return (links?.relations ?? noRelations).filter((relation) => !omitted.has(relation.predicate));
|
|
40
|
+
}, [links, omitPredicates]);
|
|
41
|
+
const shown = useMemo(() => new Set(listed.map((relation) => relation.target)), [listed]);
|
|
17
42
|
|
|
18
43
|
return (
|
|
19
44
|
<div className="w-fit flex flex-col items-start gap-1" onContextMenu={onContextMenu}>
|
|
@@ -34,7 +59,16 @@ export const EntityCardShell = memo(function EntityCardShell(props: EntityCardSh
|
|
|
34
59
|
)}
|
|
35
60
|
style={selected && ringColor ? { boxShadow: `0 0 0 1.5px ${ringColor}` } : undefined}
|
|
36
61
|
>
|
|
37
|
-
{
|
|
62
|
+
<CardContentProvider shown={shown}>
|
|
63
|
+
{isPresent(listed) ? (
|
|
64
|
+
<div className="overflow-hidden rounded-md bg-muted">
|
|
65
|
+
<RelatedSection relations={listed} />
|
|
66
|
+
{children}
|
|
67
|
+
</div>
|
|
68
|
+
) : (
|
|
69
|
+
children
|
|
70
|
+
)}
|
|
71
|
+
</CardContentProvider>
|
|
38
72
|
</div>
|
|
39
73
|
</div>
|
|
40
74
|
);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
+
import type { IRI } from "@manta-eu/rdf-lib/namespaces";
|
|
1
3
|
import { useCallback, useMemo } from "react";
|
|
4
|
+
import { useLinksShownAbove } from "../card-links";
|
|
2
5
|
import { shouldHidePreviewField } from "../graph-list-utils";
|
|
3
6
|
import { AttributeList, useAttributeFacts } from "../special-nodes/AttributeList";
|
|
4
7
|
import type { NodeProperty, NodeRelation } from "../types";
|
|
@@ -17,7 +20,7 @@ export type NodePropertyTableProps = {
|
|
|
17
20
|
// The node's raw values, so a multi-valued property renders as tags rather than a joined string.
|
|
18
21
|
jsonLd?: Record<string, unknown>;
|
|
19
22
|
// Rendered above the table by the card itself, so the table skips them.
|
|
20
|
-
omitPredicates?: readonly
|
|
23
|
+
omitPredicates?: readonly IRI[];
|
|
21
24
|
relations?: NodeRelation[];
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -45,6 +48,17 @@ export function NodePropertyTable(props: NodePropertyTableProps) {
|
|
|
45
48
|
);
|
|
46
49
|
|
|
47
50
|
const { facts, previewCount } = useAttributeFacts({ properties, relations: visibleRelations, jsonLd, include });
|
|
51
|
+
const shownAbove = useLinksShownAbove();
|
|
52
|
+
const shown = useMemo(
|
|
53
|
+
() =>
|
|
54
|
+
facts.flatMap((fact) => {
|
|
55
|
+
if (!isPresent(fact.entityIris)) return [fact];
|
|
56
|
+
|
|
57
|
+
const rest = fact.entityIris.filter((iri) => !shownAbove.has(iri));
|
|
58
|
+
return isPresent(rest) ? [{ ...fact, entityIris: rest }] : [];
|
|
59
|
+
}),
|
|
60
|
+
[facts, shownAbove],
|
|
61
|
+
);
|
|
48
62
|
|
|
49
|
-
return <AttributeList facts={
|
|
63
|
+
return <AttributeList facts={shown} previewCount={previewCount} showAll />;
|
|
50
64
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isHexColor } from "@manta-eu/lib/color";
|
|
1
2
|
import { formatPercent, parseNumeric } from "../property-formatters";
|
|
2
3
|
|
|
3
4
|
export type PropertyDisplay =
|
|
@@ -9,12 +10,6 @@ export type PropertyDisplay =
|
|
|
9
10
|
| { kind: "prose"; text: string }
|
|
10
11
|
| { kind: "text"; text: string };
|
|
11
12
|
|
|
12
|
-
const hexPattern = /^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
13
|
-
|
|
14
|
-
// Shared with the palette swatch: both guard a style sink, so the two must not drift.
|
|
15
|
-
export function isHexColor(value: string): boolean {
|
|
16
|
-
return hexPattern.test(value);
|
|
17
|
-
}
|
|
18
13
|
const prosePhraseLength = 60;
|
|
19
14
|
|
|
20
15
|
// Wider than formatDisplayValue's isPercentLabel, which excludes score — merging them would change both.
|
|
@@ -36,7 +31,7 @@ export function classifyPropertyDisplay(args: { label: string; formatted: string
|
|
|
36
31
|
if (values.length > 1) return { kind: "tags", values };
|
|
37
32
|
}
|
|
38
33
|
|
|
39
|
-
if (
|
|
34
|
+
if (isHexColor(formatted)) return { kind: "color", hex: formatted };
|
|
40
35
|
|
|
41
36
|
// RDF booleans arrive as the literals "true"/"false" from the graph, as real booleans from fixtures.
|
|
42
37
|
if (raw === true || raw === false) return { kind: "boolean", value: raw };
|
|
@@ -97,8 +97,10 @@ export function AttributeList(props: AttributeListProps) {
|
|
|
97
97
|
);
|
|
98
98
|
|
|
99
99
|
const visibleFacts = searching || expanded ? matchingFacts : facts.slice(0, previewCount);
|
|
100
|
-
const hasHiddenChips = visibleFacts.some((fact) => visibleChips(fact.entityIris, expanded).hiddenCount > 0);
|
|
101
100
|
const hiddenCount = facts.length - previewCount;
|
|
101
|
+
const collapsible =
|
|
102
|
+
hiddenCount > 0 ||
|
|
103
|
+
facts.slice(0, previewCount).some((fact) => visibleChips(fact.entityIris, false).hiddenCount > 0);
|
|
102
104
|
|
|
103
105
|
if (!isPresent(facts)) return null;
|
|
104
106
|
|
|
@@ -161,7 +163,7 @@ export function AttributeList(props: AttributeListProps) {
|
|
|
161
163
|
{searching && !isPresent(visibleFacts) && (
|
|
162
164
|
<span className="typography-tiny py-1 text-muted-foreground">No matching attributes.</span>
|
|
163
165
|
)}
|
|
164
|
-
{!showAll &&
|
|
166
|
+
{!showAll && collapsible && (
|
|
165
167
|
<NodePropertyExpander
|
|
166
168
|
expanded={expanded}
|
|
167
169
|
collapsedLabel={hiddenCount > 0 ? `Show all ${facts.length}` : "Show all"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import type { NodeProperty, NodeRelation } from "../types";
|
|
4
|
+
import { AttributeList, useAttributeFacts } from "./AttributeList";
|
|
5
|
+
import { singleLinksFirst } from "./card-facts";
|
|
6
|
+
|
|
7
|
+
export type RelatedSectionProps = { relations: NodeRelation[] };
|
|
8
|
+
|
|
9
|
+
const noProperties: NodeProperty[] = [];
|
|
10
|
+
const noJsonLd: Record<string, unknown> = {};
|
|
11
|
+
|
|
12
|
+
export function RelatedSection(props: RelatedSectionProps) {
|
|
13
|
+
const { relations } = props;
|
|
14
|
+
|
|
15
|
+
const { facts, previewCount } = useAttributeFacts({ properties: noProperties, relations, jsonLd: noJsonLd });
|
|
16
|
+
const ordered = useMemo(() => singleLinksFirst(facts), [facts]);
|
|
17
|
+
|
|
18
|
+
if (!isPresent(ordered)) return null;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
role="group"
|
|
23
|
+
aria-label="Related records"
|
|
24
|
+
className="flex max-w-90 flex-col border-b border-muted-border px-3 pb-2 pt-2.5 text-default-foreground"
|
|
25
|
+
>
|
|
26
|
+
<AttributeList facts={ordered} previewCount={previewCount} />
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -107,6 +107,19 @@ export function keyWords(key: string): string[] {
|
|
|
107
107
|
.map((word) => word.toLowerCase());
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// Links to records with a name of their own, so unnamed sub-records (an insight's action rows) stay off the card.
|
|
111
|
+
export function namedRelations(relations: NodeRelation[], instanceLabels: Map<string, string | null>): NodeRelation[] {
|
|
112
|
+
return relations.filter((relation) => isPresent(instanceLabels.get(relation.target)));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// What the record belongs to (one campaign, one account) reads before what it has many of.
|
|
116
|
+
export function singleLinksFirst(facts: CardFact[]): CardFact[] {
|
|
117
|
+
return [
|
|
118
|
+
...facts.filter((fact) => fact.entityIris.length <= 1),
|
|
119
|
+
...facts.filter((fact) => fact.entityIris.length > 1),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
|
|
110
123
|
export function relationFacts(
|
|
111
124
|
relations: NodeRelation[],
|
|
112
125
|
terms: Map<string, OntologyTerm>,
|
package/src/graph/types.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type NodeProperty = {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
// A property whose value is another entity in the graph; the canvas draws it as an edge instead.
|
|
14
|
-
export type NodeRelation = { predicate:
|
|
14
|
+
export type NodeRelation = { predicate: IRI; target: IRI };
|
|
15
15
|
|
|
16
16
|
export type RDFNodeData = {
|
|
17
17
|
label: string;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { useExecuteAgentActionAdditionMutation } from "@manta-eu/client";
|
|
2
|
+
import { entityActionInput } from "@manta-eu/client/shared/action-document";
|
|
3
|
+
import { BrandAssetDecisionSchema } from "@manta-eu/ldo/schemas/brand";
|
|
2
4
|
import { isPresent } from "@manta-eu/lib/present";
|
|
3
5
|
import { isValidFullIri, namespaces } from "@manta-eu/rdf-lib/namespaces";
|
|
4
6
|
import { useQueryClient } from "@tanstack/react-query";
|
|
@@ -8,13 +10,12 @@ import { useCallback, useMemo, useRef, useState } from "react";
|
|
|
8
10
|
import { toast } from "sonner";
|
|
9
11
|
import type { ManualAction } from "./use-manual-actions";
|
|
10
12
|
import { useSparqlSelect } from "./use-sparql-construct";
|
|
11
|
-
import {
|
|
13
|
+
import { mintSubjectIri } from "#lib/action-document";
|
|
12
14
|
import { useMantaClient } from "#providers/MantaClientProvider";
|
|
13
15
|
import { invalidateActionPlanQueries } from "#shared/query-keys";
|
|
14
16
|
|
|
15
17
|
const df = new DataFactory();
|
|
16
18
|
const assetAnalysis = `${namespaces.brand}AssetAnalysis`;
|
|
17
|
-
const assetDecision = `${namespaces.brand}AssetDecision`;
|
|
18
19
|
const decideAssetShape = `${namespaces.brand}DecideAssetShape`;
|
|
19
20
|
|
|
20
21
|
export type ApproveAnywayHandle = {
|
|
@@ -68,16 +69,12 @@ export function useApproveAnyway(planGraphIri: string): ApproveAnywayHandle {
|
|
|
68
69
|
if (inFlight.current.has(analysisIri)) return;
|
|
69
70
|
inFlight.current.add(analysisIri);
|
|
70
71
|
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
72
|
void startAddition({
|
|
80
|
-
input:
|
|
73
|
+
input: entityActionInput(BrandAssetDecisionSchema, decideAssetShape, {
|
|
74
|
+
$id: mintSubjectIri(BrandAssetDecisionSchema["@type"]),
|
|
75
|
+
decisionOnAsset: analysisIri,
|
|
76
|
+
decision: "approved",
|
|
77
|
+
}),
|
|
81
78
|
})
|
|
82
79
|
.then(({ executeActionAddition }) => {
|
|
83
80
|
if (!executeActionAddition.success) throw new Error(executeActionAddition.error ?? "The approval failed");
|
package/src/ldo-ui.ts
CHANGED
|
@@ -344,6 +344,7 @@ export {
|
|
|
344
344
|
export { NodeFrame, type NodeFrameProps } from "./graph/special-nodes/NodeFrame";
|
|
345
345
|
|
|
346
346
|
export { EntityCard, findEntityNode, type EntityCardProps } from "./graph/EntityCard";
|
|
347
|
+
export { EntityViewWithLinks, type EntityViewWithLinksProps } from "./graph/EntityViewWithLinks";
|
|
347
348
|
export { findDetailViewForTypes, findPluralViewForTypes, type DetailView, type PluralView } from "./graph/detail-views";
|
|
348
349
|
export { EntityStripDisplay, type EntityStripDisplayProps } from "./graph/EntityStripDisplay";
|
|
349
350
|
export { stubNodeData } from "./graph/stub-node";
|
package/src/lib/chat-types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable import/order -- each type is imported beside the re-export it exists for, which is
|
|
2
2
|
how this file is organized; they are type-only, so the positions have no runtime meaning. */
|
|
3
|
+
import type { ConversationMode } from "@manta-eu/client/shared/chat-manager";
|
|
3
4
|
import type { MantaModelId } from "@manta-eu/client/shared/model";
|
|
4
5
|
import type { ReactNode } from "react";
|
|
5
6
|
import type { Datastore } from "#ldo-ui";
|
|
@@ -26,6 +27,21 @@ export type CopilotMenuDefaults = {
|
|
|
26
27
|
|
|
27
28
|
export type ChatDraft = { id: string; text: string };
|
|
28
29
|
|
|
30
|
+
export type ChatStartupReport = {
|
|
31
|
+
surface: "embedded" | "app";
|
|
32
|
+
mode: "ticket" | "cookie";
|
|
33
|
+
openIndex: number;
|
|
34
|
+
hostTokenMs?: number;
|
|
35
|
+
ticketMs?: number;
|
|
36
|
+
ticketAttempts?: number;
|
|
37
|
+
socketMs: number;
|
|
38
|
+
socketAttempts: number;
|
|
39
|
+
chatMountMs: number;
|
|
40
|
+
socketReadyAtOpen: boolean;
|
|
41
|
+
firstPaintMs: number;
|
|
42
|
+
interactiveMs: number;
|
|
43
|
+
};
|
|
44
|
+
|
|
29
45
|
// NOTE: Adding to this is a breaking change to library clients
|
|
30
46
|
export type AuthenticatedChatProps = {
|
|
31
47
|
datastore?: Datastore;
|
|
@@ -39,6 +55,7 @@ export type AuthenticatedChatProps = {
|
|
|
39
55
|
collapsible?: boolean;
|
|
40
56
|
isCollapsed?: boolean;
|
|
41
57
|
pageContext?: PageContext;
|
|
58
|
+
mode?: ConversationMode;
|
|
42
59
|
allowedModels?: MantaModelId[];
|
|
43
60
|
initialPrompt?: string;
|
|
44
61
|
initialDraft?: ChatDraft;
|
|
@@ -48,6 +65,7 @@ export type AuthenticatedChatProps = {
|
|
|
48
65
|
assistantIcon?: AssistantIcon;
|
|
49
66
|
mark?: ReactNode;
|
|
50
67
|
renderMenuItems?: (defaults: CopilotMenuDefaults) => ReactNode[];
|
|
68
|
+
onStartupTiming?: (report: ChatStartupReport) => void;
|
|
51
69
|
};
|
|
52
70
|
|
|
53
71
|
export type ResolvedChatProps = AuthenticatedChatProps & {
|