@manta-eu/react 0.2.1 → 0.4.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/dist/components/datastore-management/tree.d.ts +1 -1
- package/dist/components/datastore-management/tree.d.ts.map +1 -1
- package/dist/components/datastore-management/tree.js +5 -5
- package/dist/components/datastore-management/tree.js.map +1 -1
- package/dist/components/explain-fact/ExplainFact.js +3 -3
- package/dist/components/explain-fact/ExplainFact.js.map +1 -1
- package/dist/components/planning/plan-detail-utils.d.ts.map +1 -1
- package/dist/components/planning/plan-detail-utils.js +4 -0
- package/dist/components/planning/plan-detail-utils.js.map +1 -1
- package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts +2 -2
- package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts.map +1 -1
- package/dist/components/tool-invocation-card/ToolOutputRenderer.d.ts.map +1 -1
- package/dist/components/tool-invocation-card/ToolOutputRenderer.js +7 -4
- package/dist/components/tool-invocation-card/ToolOutputRenderer.js.map +1 -1
- package/dist/components/tool-invocation-card/types.d.ts +5 -5
- package/dist/components/tool-invocation-card/types.d.ts.map +1 -1
- package/dist/components/tool-invocation-card/types.js +5 -5
- package/dist/components/tool-invocation-card/types.js.map +1 -1
- package/dist/explain-fact/rule-presentation.js +2 -2
- package/dist/explain-fact/rule-presentation.js.map +1 -1
- package/dist/explain-fact/tree-model.js +2 -2
- package/dist/explain-fact/tree-model.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/find-latest-staged-rule.js +1 -1
- package/dist/lib/find-latest-staged-rule.js.map +1 -1
- package/dist/lib/tool-icons.js +6 -6
- package/dist/lib/tool-icons.js.map +1 -1
- package/dist/lib/tool-names.d.ts.map +1 -1
- package/dist/lib/tool-names.js +0 -1
- package/dist/lib/tool-names.js.map +1 -1
- package/dist/ontology/skolem.js +2 -2
- package/dist/ontology/skolem.js.map +1 -1
- package/dist/providers/KnowledgeGraphStateProvider.js +1 -1
- package/dist/providers/KnowledgeGraphStateProvider.js.map +1 -1
- package/dist/routes/data-explorer/class-properties.js +2 -2
- package/dist/routes/data-explorer/class-properties.js.map +1 -1
- package/dist/routes/data-explorer/classes.js +2 -2
- package/dist/routes/data-explorer/classes.js.map +1 -1
- 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/data-explorer/recents.js +1 -1
- package/dist/routes/data-explorer/recents.js.map +1 -1
- package/dist/routes/data-explorer/shapes.js +2 -2
- package/dist/routes/data-explorer/shapes.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/CanvaConnectForm.d.ts +3 -0
- package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.d.ts.map +1 -0
- package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js +12 -0
- package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js.map +1 -0
- 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 +3 -0
- package/dist/routes/integrations/connect-forms.d.ts.map +1 -1
- package/dist/routes/integrations/connect-forms.js +3 -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 +2 -0
- package/dist/routes/integrations/connection-view.js.map +1 -1
- package/dist/routes/integrations/types.d.ts +2 -1
- package/dist/routes/integrations/types.d.ts.map +1 -1
- package/dist/routes/integrations/types.js +1 -0
- package/dist/routes/integrations/types.js.map +1 -1
- package/dist/routes/rules/hooks/useRuleFactsPreview.js +4 -4
- package/dist/routes/rules/hooks/useRuleFactsPreview.js.map +1 -1
- package/dist/shacl/form-appearance.d.ts +1 -1
- package/dist/shacl/form-appearance.d.ts.map +1 -1
- package/dist/shacl/form-appearance.js +1 -1
- package/dist/shacl/form-appearance.js.map +1 -1
- package/dist/shared/graph-derived-queries.js +2 -2
- package/dist/shared/graph-derived-queries.js.map +1 -1
- package/package.json +7 -7
- package/src/components/datastore-management/tree.ts +5 -5
- package/src/components/explain-fact/ExplainFact.tsx +3 -3
- package/src/components/planning/plan-detail-utils.tsx +4 -0
- package/src/components/tool-invocation-card/ListRulesResultDisplay.tsx +2 -2
- package/src/components/tool-invocation-card/ToolOutputRenderer.tsx +10 -8
- package/src/components/tool-invocation-card/types.ts +8 -8
- package/src/explain-fact/rule-presentation.ts +2 -2
- package/src/explain-fact/tree-model.ts +2 -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/find-latest-staged-rule.ts +1 -1
- package/src/lib/tool-icons.ts +6 -6
- package/src/lib/tool-names.ts +0 -1
- package/src/ontology/skolem.ts +2 -2
- package/src/providers/KnowledgeGraphStateProvider.tsx +1 -1
- package/src/routes/data-explorer/class-properties.ts +2 -2
- package/src/routes/data-explorer/classes.ts +2 -2
- 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/data-explorer/recents.ts +1 -1
- package/src/routes/data-explorer/shapes.ts +2 -2
- package/src/routes/datastores/flatten.ts +1 -1
- package/src/routes/integrations/catalog-shape.ts +2 -0
- package/src/routes/integrations/components/connect-forms/CanvaConnectForm.tsx +26 -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 +3 -0
- package/src/routes/integrations/connection-view.ts +2 -0
- package/src/routes/integrations/types.ts +2 -0
- package/src/routes/rules/hooks/useRuleFactsPreview.ts +4 -4
- package/src/shacl/form-appearance.ts +1 -1
- package/src/shared/graph-derived-queries.ts +2 -2
|
@@ -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";
|
|
@@ -3,5 +3,5 @@ import { isStagedManageRulesResult } from "../components/tool-invocation-card/ty
|
|
|
3
3
|
import { findLatestToolOutput } from "./find-latest-tool-output";
|
|
4
4
|
|
|
5
5
|
export function findLatestStagedRuleIri(messages: ChatUIMessage[]): string | null {
|
|
6
|
-
return findLatestToolOutput(messages, "tool-
|
|
6
|
+
return findLatestToolOutput(messages, "tool-manageRules", isStagedManageRulesResult)?.ruleIri ?? null;
|
|
7
7
|
}
|
package/src/lib/tool-icons.ts
CHANGED
|
@@ -27,12 +27,12 @@ import {
|
|
|
27
27
|
import { match } from "ts-pattern";
|
|
28
28
|
|
|
29
29
|
const toolIconMap: Record<ToolName, LucideIcon> = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
queryKnowledgeGraph: Database,
|
|
31
|
+
addFacts: Database,
|
|
32
|
+
manageFacts: Database,
|
|
33
|
+
getRules: Brain,
|
|
34
|
+
explainFact: Brain,
|
|
35
|
+
manageRules: Brain,
|
|
36
36
|
generateChart: TrendingUp,
|
|
37
37
|
scheduleTask: Clock,
|
|
38
38
|
listScheduledTasks: Clock,
|
package/src/lib/tool-names.ts
CHANGED
package/src/ontology/skolem.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type SkolemPart = { type: "iri"; value: string } | { type: "literal"; val
|
|
|
5
5
|
const blankNodePrefixes = ["_:", "_."];
|
|
6
6
|
const segmentTagLength = 2;
|
|
7
7
|
|
|
8
|
-
//
|
|
8
|
+
// The datastore datatype tags: "02" = IRI, "05" = string; other datatypes are binary-encoded.
|
|
9
9
|
const segmentTypeByTag: Record<string, SkolemPart["type"]> = {
|
|
10
10
|
"02": "iri",
|
|
11
11
|
"05": "literal",
|
|
@@ -29,7 +29,7 @@ function decodeSegment(segment: string): string | undefined {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
//
|
|
32
|
+
// The datastore skolem labels: dot-separated base64 segments, each prefixed with a 2-char type tag.
|
|
33
33
|
export function decodeSkolem(term: string): SkolemPart[] | undefined {
|
|
34
34
|
const prefix = blankNodePrefixes.find((candidate) => term.startsWith(candidate));
|
|
35
35
|
|
|
@@ -135,7 +135,7 @@ export function KnowledgeGraphStateProvider(props: KnowledgeGraphStateProviderPr
|
|
|
135
135
|
|
|
136
136
|
if (currentDataVersion && isPresent(previousDataVersion) && previousDataVersion !== currentDataVersion) {
|
|
137
137
|
void invalidateGraphDerivedQueries(queryClient);
|
|
138
|
-
console.debug("Knowledge graph dataVersion changed, invalidating
|
|
138
|
+
console.debug("Knowledge graph dataVersion changed, invalidating the knowledge graph queries");
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
if (currentDataVersion && currentDataVersion !== previousDataVersion) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ontologyGraphIri,
|
|
1
|
+
import { ontologyGraphIri, shaclGraph } from "@manta-eu/client/shared/rdf-namespaces";
|
|
2
2
|
import { isPresent } from "@manta-eu/lib/present";
|
|
3
3
|
import { DataFactory } from "ldkit/rdf";
|
|
4
4
|
import { SELECT } from "ldkit/sparql";
|
|
@@ -32,7 +32,7 @@ function classPropertiesQuery(classIri: string): string {
|
|
|
32
32
|
|
|
33
33
|
function shapeConstraintsQuery(classIri: string): string {
|
|
34
34
|
return `${prefixes}${SELECT`?path ?minCount ?allowedValue`.WHERE`
|
|
35
|
-
VALUES ?shapeGraph { ${df.namedNode(ontologyGraphIri)} ${df.namedNode(
|
|
35
|
+
VALUES ?shapeGraph { ${df.namedNode(ontologyGraphIri)} ${df.namedNode(shaclGraph)} }
|
|
36
36
|
GRAPH ?shapeGraph {
|
|
37
37
|
?shape sh:targetClass ${df.namedNode(safeIri(classIri))} ; sh:property ?propertyShape .
|
|
38
38
|
?propertyShape sh:path ?path .
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ontologyGraphIri,
|
|
1
|
+
import { ontologyGraphIri, shaclGraph } from "@manta-eu/client/shared/rdf-namespaces";
|
|
2
2
|
import { isPresent } from "@manta-eu/lib/present";
|
|
3
3
|
import { DataFactory, type RDF } from "ldkit/rdf";
|
|
4
4
|
import { SELECT } from "ldkit/sparql";
|
|
@@ -33,7 +33,7 @@ const classesQuery = `${prefixes}${SELECT.DISTINCT`?class ?label ?comment`.WHERE
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
UNION {
|
|
36
|
-
GRAPH ${df.namedNode(
|
|
36
|
+
GRAPH ${df.namedNode(shaclGraph)} { ?shapeInShaclGraph sh:targetClass ?class }
|
|
37
37
|
}
|
|
38
38
|
OPTIONAL { GRAPH ${df.namedNode(ontologyGraphIri)} { ?class rdfs:label ?label } }
|
|
39
39
|
OPTIONAL { GRAPH ${df.namedNode(ontologyGraphIri)} { ?class rdfs:comment ?comment } }
|
|
@@ -59,7 +59,6 @@ export function ActionFormDialog(props: ActionFormDialogProps) {
|
|
|
59
59
|
const baselineRef = useRef<PropertyMap | null>(null);
|
|
60
60
|
const [refusal, setRefusal] = useState<string | null>(null);
|
|
61
61
|
const [formElement, setFormElement] = useState<ShaclFormElement | null>(null);
|
|
62
|
-
const [isReadingForm, setIsReadingForm] = useState(false);
|
|
63
62
|
|
|
64
63
|
const attachForm = useCallback((element: ShaclFormElement | null) => setFormElement(element), []);
|
|
65
64
|
|
|
@@ -77,29 +76,20 @@ export function ActionFormDialog(props: ActionFormDialogProps) {
|
|
|
77
76
|
useEffect(() => {
|
|
78
77
|
if (!formElement || !isUpdate) return;
|
|
79
78
|
|
|
80
|
-
let cancelled = false;
|
|
81
|
-
|
|
82
79
|
// Baseline is the form's own serialization: its editors normalize literals, the triples do not.
|
|
83
|
-
|
|
80
|
+
function onReady() {
|
|
84
81
|
const store = formElement?.toRDF();
|
|
85
|
-
const baseline = store ?
|
|
86
|
-
|
|
87
|
-
if (baseline && !cancelled) baselineRef.current = baseline;
|
|
88
|
-
}
|
|
82
|
+
const baseline = store ? baselineFromStore(store, subjectIri) : null;
|
|
89
83
|
|
|
90
|
-
|
|
91
|
-
void captureBaseline();
|
|
84
|
+
if (baseline) baselineRef.current = baseline;
|
|
92
85
|
}
|
|
93
86
|
|
|
94
87
|
onReady();
|
|
95
88
|
formElement.addEventListener("ready", onReady);
|
|
96
|
-
return () =>
|
|
97
|
-
cancelled = true;
|
|
98
|
-
formElement.removeEventListener("ready", onReady);
|
|
99
|
-
};
|
|
89
|
+
return () => formElement.removeEventListener("ready", onReady);
|
|
100
90
|
}, [formElement, isUpdate, subjectIri]);
|
|
101
91
|
|
|
102
|
-
|
|
92
|
+
function submit() {
|
|
103
93
|
const store = formElement?.toRDF();
|
|
104
94
|
const baseline = baselineRef.current;
|
|
105
95
|
|
|
@@ -108,14 +98,7 @@ export function ActionFormDialog(props: ActionFormDialogProps) {
|
|
|
108
98
|
return;
|
|
109
99
|
}
|
|
110
100
|
|
|
111
|
-
|
|
112
|
-
const edited = await propertiesFromStore(store, subjectIri).catch(() => null);
|
|
113
|
-
setIsReadingForm(false);
|
|
114
|
-
|
|
115
|
-
if (!edited) {
|
|
116
|
-
setRefusal("The form could not be read.");
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
101
|
+
const edited = propertiesFromStore(store, subjectIri);
|
|
119
102
|
|
|
120
103
|
if (isUpdate && baseline) {
|
|
121
104
|
const cleared = removedPredicates(baseline, edited);
|
|
@@ -176,12 +159,7 @@ export function ActionFormDialog(props: ActionFormDialogProps) {
|
|
|
176
159
|
<Button variant="tertiary" size="sm" onClick={() => onOpenChange(false)}>
|
|
177
160
|
Cancel
|
|
178
161
|
</Button>
|
|
179
|
-
<Button
|
|
180
|
-
size="sm"
|
|
181
|
-
onClick={() => void submit()}
|
|
182
|
-
isLoading={isPending || isReadingForm}
|
|
183
|
-
disabled={!shapesTurtle}
|
|
184
|
-
>
|
|
162
|
+
<Button size="sm" onClick={submit} isLoading={isPending} disabled={!shapesTurtle}>
|
|
185
163
|
{copy.submitLabel}
|
|
186
164
|
</Button>
|
|
187
165
|
</DialogFooter>
|
|
@@ -7,6 +7,7 @@ import { actionShapesForTypes } from "./action-shapes";
|
|
|
7
7
|
import { Badge } from "#components/badge/index";
|
|
8
8
|
import {
|
|
9
9
|
type ActionShapeSpec,
|
|
10
|
+
EntityViewWithLinks,
|
|
10
11
|
findEntityNode,
|
|
11
12
|
GenericView,
|
|
12
13
|
getEntityView,
|
|
@@ -97,7 +98,11 @@ export function ChatPreview(props: ChatPreviewProps) {
|
|
|
97
98
|
<section>
|
|
98
99
|
<h3 className={cn(sectionLabelClass, "mb-1.5 text-muted-foreground")}>Chat rendering</h3>
|
|
99
100
|
<div className="max-w-md">
|
|
100
|
-
{EntityView ?
|
|
101
|
+
{EntityView ? (
|
|
102
|
+
<EntityViewWithLinks view={EntityView} data={node.data} />
|
|
103
|
+
) : (
|
|
104
|
+
<GenericView data={node.data} defaultExpanded />
|
|
105
|
+
)}
|
|
101
106
|
</div>
|
|
102
107
|
</section>
|
|
103
108
|
|
|
@@ -7,14 +7,14 @@ export type PropertyMap = Record<string, unknown>;
|
|
|
7
7
|
// The form stamps this on every serialization
|
|
8
8
|
const conformsTo = `${namespaces.dcterms}conformsTo`;
|
|
9
9
|
|
|
10
|
-
export
|
|
10
|
+
export function propertiesFromStore(store: ShaclFormStore, subjectIri: string): PropertyMap {
|
|
11
11
|
const quads = [...store].filter((quad) => quad.predicate.value !== conformsTo);
|
|
12
|
-
const { "@id": _id, "@type": _type, ...properties } =
|
|
12
|
+
const { "@id": _id, "@type": _type, ...properties } = documentFromQuads(quads, subjectIri);
|
|
13
13
|
|
|
14
14
|
return properties;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export
|
|
17
|
+
export function baselineFromStore(store: ShaclFormStore, subjectIri: string): PropertyMap | null {
|
|
18
18
|
if (store.size === 0) return null;
|
|
19
19
|
|
|
20
20
|
return propertiesFromStore(store, subjectIri);
|
|
@@ -19,7 +19,7 @@ const df = new DataFactory();
|
|
|
19
19
|
|
|
20
20
|
export const recentTypesLimit = 10;
|
|
21
21
|
|
|
22
|
-
// STR() ordering because sources mix xsd:date and xsd:dateTime, which
|
|
22
|
+
// STR() ordering because sources mix xsd:date and xsd:dateTime, which the datastore will not compare as temporals
|
|
23
23
|
const recentlyModifiedTypesSubquery = SELECT`?type (MAX(STR(?modified)) AS ?lastModified)`.WHERE`
|
|
24
24
|
?dated schema:dateModified ?modified .
|
|
25
25
|
?dated a ?type .
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ontologyGraphIri,
|
|
1
|
+
import { ontologyGraphIri, shaclGraph } from "@manta-eu/client/shared/rdf-namespaces";
|
|
2
2
|
import { isPresent } from "@manta-eu/lib/present";
|
|
3
3
|
import { DataFactory, type RDF } from "ldkit/rdf";
|
|
4
4
|
import { SELECT } from "ldkit/sparql";
|
|
@@ -62,7 +62,7 @@ export function groupShapeConstraints(rows: ShapeConstraintRow[]): ClassShape[]
|
|
|
62
62
|
|
|
63
63
|
function shapeDetailsQuery(classIri: string): string {
|
|
64
64
|
return `${prefixes}${SELECT.DISTINCT`?shape ?path ?constraint ?value ?listValue`.WHERE`
|
|
65
|
-
VALUES ?shapeGraph { ${df.namedNode(ontologyGraphIri)} ${df.namedNode(
|
|
65
|
+
VALUES ?shapeGraph { ${df.namedNode(ontologyGraphIri)} ${df.namedNode(shaclGraph)} }
|
|
66
66
|
GRAPH ?shapeGraph {
|
|
67
67
|
?shape sh:targetClass ${df.namedNode(safeIri(classIri))} ; sh:property ?propertyShape .
|
|
68
68
|
?propertyShape sh:path ?path ; ?constraint ?value .
|
|
@@ -22,7 +22,7 @@ export type DatastoreRow = {
|
|
|
22
22
|
// Org roots carry their own datastore but are also the container the rest hang off.
|
|
23
23
|
isOrganization: boolean;
|
|
24
24
|
mirrored?: boolean;
|
|
25
|
-
// Real in
|
|
25
|
+
// Real in the datastore, but no Keycloak node behind it, so it can only be selected.
|
|
26
26
|
isRealmDefault?: boolean;
|
|
27
27
|
isUnlinked?: boolean;
|
|
28
28
|
};
|
|
@@ -22,6 +22,8 @@ export type OAuthConnectionMethod = ConnectionMethodBase & {
|
|
|
22
22
|
source: "oauth";
|
|
23
23
|
integration: GQLIntegration;
|
|
24
24
|
callbackProvider?: string;
|
|
25
|
+
// Further oauth_provider values whose callback resumes this same method, e.g. a second identity provider.
|
|
26
|
+
alternateCallbackProviders?: readonly string[];
|
|
25
27
|
resumesSetupAfterOAuth?: boolean;
|
|
26
28
|
connectedAction?: ComponentType;
|
|
27
29
|
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { GQLIntegration } from "@manta-eu/client";
|
|
2
|
+
import { OAuthSingleAccountConnectForm } from "./OAuthSingleAccountConnectForm";
|
|
3
|
+
import type { ConnectFormProps } from "./types";
|
|
4
|
+
|
|
5
|
+
const canvaPermissions = [
|
|
6
|
+
"Read your designs, the folders they live in, and your uploaded assets.",
|
|
7
|
+
"Export your designs so their pages can be analyzed.",
|
|
8
|
+
"Read your brand templates and the comments on your designs.",
|
|
9
|
+
];
|
|
10
|
+
|
|
11
|
+
export function CanvaConnectForm(props: ConnectFormProps) {
|
|
12
|
+
return (
|
|
13
|
+
<OAuthSingleAccountConnectForm
|
|
14
|
+
{...props}
|
|
15
|
+
integration={GQLIntegration.Canva}
|
|
16
|
+
startHref="/oauth/canva/start"
|
|
17
|
+
ctaLabel="Continue with Canva"
|
|
18
|
+
stepTitle="Connect your Canva account"
|
|
19
|
+
stepDescription="Manta will take you to Canva to ask for permission, then bring you back here."
|
|
20
|
+
supportingInfo="You'll be taken to Canva to approve access. You can revoke it any time from your Canva account settings."
|
|
21
|
+
permissions={canvaPermissions}
|
|
22
|
+
waitingLabel="Waiting for you to finish connecting to Canva…"
|
|
23
|
+
connectedToastLabel="Canva connected"
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|