@manta-eu/react 0.1.10 → 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/chat-view/ChatTurnErrorNotice.d.ts.map +1 -1
- package/dist/components/chat-view/ChatTurnErrorNotice.js +3 -1
- package/dist/components/chat-view/ChatTurnErrorNotice.js.map +1 -1
- package/dist/components/layouts/ConnectedCustomApp.d.ts +13 -0
- package/dist/components/layouts/ConnectedCustomApp.d.ts.map +1 -0
- package/dist/components/layouts/ConnectedCustomApp.js +37 -0
- package/dist/components/layouts/ConnectedCustomApp.js.map +1 -0
- package/dist/components/layouts/Sidebar.d.ts.map +1 -1
- package/dist/components/layouts/Sidebar.js +6 -3
- package/dist/components/layouts/Sidebar.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/table-skeleton/index.d.ts +2 -0
- package/dist/components/table-skeleton/index.d.ts.map +1 -1
- package/dist/components/table-skeleton/index.js +2 -1
- package/dist/components/table-skeleton/index.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/createNodeRouter.js +3 -3
- package/dist/graph/createNodeRouter.js.map +1 -1
- 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 +3 -0
- package/dist/graph/nodes/BrandFontSuggestionView.d.ts.map +1 -0
- package/dist/graph/nodes/{BrandFontFamilyView.js → BrandFontSuggestionView.js} +22 -13
- package/dist/graph/nodes/BrandFontSuggestionView.js.map +1 -0
- 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/brand-font.d.ts +8 -0
- package/dist/graph/nodes/brand-font.d.ts.map +1 -1
- package/dist/graph/nodes/brand-font.js +6 -0
- package/dist/graph/nodes/brand-font.js.map +1 -1
- package/dist/graph/nodes/brand-shared.d.ts +0 -3
- package/dist/graph/nodes/brand-shared.d.ts.map +1 -1
- package/dist/graph/nodes/brand-shared.js +1 -4
- package/dist/graph/nodes/brand-shared.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/useAuth.d.ts +2 -2
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +2 -2
- package/dist/hooks/useAuth.js.map +1 -1
- package/dist/hooks/useOnboardingState.js +1 -1
- package/dist/hooks/useOnboardingState.js.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/datastore-route-table.d.ts +2 -1
- package/dist/lib/datastore-route-table.d.ts.map +1 -1
- package/dist/lib/datastore-route-table.js +2 -1
- package/dist/lib/datastore-route-table.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/AuthContext.d.ts +2 -1
- package/dist/providers/AuthContext.d.ts.map +1 -1
- package/dist/providers/AuthContext.js.map +1 -1
- package/dist/providers/ChatManagerProvider.d.ts.map +1 -1
- package/dist/providers/ChatManagerProvider.js +22 -9
- 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/data-explorer/declared-namespaces.d.ts +3 -0
- package/dist/routes/data-explorer/declared-namespaces.d.ts.map +1 -1
- package/dist/routes/data-explorer/declared-namespaces.js +21 -13
- package/dist/routes/data-explorer/declared-namespaces.js.map +1 -1
- package/dist/routes/data-explorer/namespaces.d.ts +1 -0
- package/dist/routes/data-explorer/namespaces.d.ts.map +1 -1
- package/dist/routes/data-explorer/namespaces.js +7 -6
- package/dist/routes/data-explorer/namespaces.js.map +1 -1
- package/dist/routes/datastores/components/DeleteDatastoreDialog.d.ts +10 -0
- package/dist/routes/datastores/components/DeleteDatastoreDialog.d.ts.map +1 -0
- package/dist/routes/datastores/components/DeleteDatastoreDialog.js +20 -0
- package/dist/routes/datastores/components/DeleteDatastoreDialog.js.map +1 -0
- package/dist/routes/datastores/flatten.d.ts +1 -0
- package/dist/routes/datastores/flatten.d.ts.map +1 -1
- package/dist/routes/datastores/flatten.js +17 -0
- package/dist/routes/datastores/flatten.js.map +1 -1
- package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts +3 -1
- package/dist/routes/datastores/hooks/useDatastoreColumns.d.ts.map +1 -1
- package/dist/routes/datastores/hooks/useDatastoreColumns.js +14 -6
- package/dist/routes/datastores/hooks/useDatastoreColumns.js.map +1 -1
- package/dist/routes/datastores/index.d.ts.map +1 -1
- package/dist/routes/datastores/index.js +31 -5
- package/dist/routes/datastores/index.js.map +1 -1
- package/dist/routes/integrations/components/ProviderGroup.js +2 -2
- package/dist/routes/integrations/components/ProviderGroup.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/chat-view/ChatTurnErrorNotice.tsx +3 -1
- package/src/components/layouts/ConnectedCustomApp.tsx +63 -0
- package/src/components/layouts/Sidebar.tsx +9 -3
- 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/table-skeleton/index.tsx +7 -1
- package/src/components/tooltip/index.tsx +35 -2
- package/src/graph/createNodeRouter.tsx +3 -3
- 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/{BrandFontFamilyView.tsx → BrandFontSuggestionView.tsx} +41 -27
- package/src/graph/nodes/BrandGuidelinesView.tsx +1 -1
- package/src/graph/nodes/NodePropertyTable.tsx +32 -143
- package/src/graph/nodes/brand-font.ts +17 -0
- package/src/graph/nodes/brand-shared.tsx +1 -4
- 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/hooks/useAuth.ts +3 -3
- package/src/hooks/useOnboardingState.ts +1 -1
- package/src/ldo-ui.ts +8 -0
- package/src/lib/datastore-route-table.ts +4 -2
- package/src/lib/manual-actions.ts +3 -2
- package/src/providers/ActiveChatProvider.tsx +3 -1
- package/src/providers/AuthContext.ts +3 -1
- package/src/providers/ChatManagerProvider.tsx +19 -9
- 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/data-explorer/declared-namespaces.ts +21 -13
- package/src/routes/data-explorer/namespaces.ts +7 -6
- package/src/routes/datastores/components/DeleteDatastoreDialog.tsx +78 -0
- package/src/routes/datastores/flatten.ts +15 -0
- package/src/routes/datastores/hooks/useDatastoreColumns.tsx +88 -49
- package/src/routes/datastores/index.tsx +41 -2
- package/src/routes/integrations/components/ProviderGroup.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/graph/nodes/BrandFontFamilyView.d.ts +0 -3
- package/dist/graph/nodes/BrandFontFamilyView.d.ts.map +0 -1
- package/dist/graph/nodes/BrandFontFamilyView.js.map +0 -1
- package/dist/graph/nodes/BrandFontUploadButton.d.ts +0 -6
- package/dist/graph/nodes/BrandFontUploadButton.d.ts.map +0 -1
- package/dist/graph/nodes/BrandFontUploadButton.js +0 -69
- package/dist/graph/nodes/BrandFontUploadButton.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/graph/nodes/BrandFontUploadButton.tsx +0 -95
- package/src/routes/data-explorer/components/TruncateTooltip.tsx +0 -25
|
@@ -1,47 +1,24 @@
|
|
|
1
|
-
import { isPresent } from "@manta-eu/lib/present";
|
|
2
|
-
import { expandPrefix } from "@manta-eu/rdf-lib/namespaces";
|
|
3
1
|
import { ChevronRight } from "lucide-react";
|
|
4
2
|
import { memo, useCallback, useMemo } from "react";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "../graph-list-utils";
|
|
11
|
-
import { ontologyTermIrisForProperties, withOntologyLabels } from "../ontology-labels";
|
|
12
|
-
import { rdfTypeColors } from "../rdf-type-colors";
|
|
13
|
-
import { statusColors } from "../status-utils";
|
|
14
|
-
import { useGraphTheme } from "../themes";
|
|
15
|
-
import type { EntityViewProps } from "../types";
|
|
3
|
+
import type { PreviewFieldHints } from "../graph-list-utils";
|
|
4
|
+
import { statusBadgeVariant } from "../status-utils";
|
|
5
|
+
import type { EntityViewProps, NodeProperty } from "../types";
|
|
6
|
+
import { AttributeList, useAttributeFacts } from "./AttributeList";
|
|
7
|
+
import { typeColor } from "./card-facts";
|
|
16
8
|
import { getStatus } from "./node-data";
|
|
17
|
-
import {
|
|
9
|
+
import { Badge } from "#components/badge/index";
|
|
18
10
|
import { cn } from "#style";
|
|
19
11
|
|
|
20
|
-
const defaultColor = "#6b7280";
|
|
21
|
-
const explainCardMaxFacts = 5;
|
|
22
|
-
|
|
23
|
-
type CardFact = { label: string; value: string; highlighted: boolean };
|
|
24
|
-
|
|
25
|
-
function getNodeColor(type?: string): string {
|
|
26
|
-
if (!type) return defaultColor;
|
|
27
|
-
return rdfTypeColors[type] ?? rdfTypeColors[expandPrefix(type)] ?? defaultColor;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function getStatusStyle(status: string): { bg: string; text: string } {
|
|
31
|
-
return statusColors[status.toLowerCase()] ?? { bg: "#94a3b8", text: "#ffffff" };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
12
|
export type GenericViewProps = EntityViewProps & {
|
|
35
13
|
previewHints?: PreviewFieldHints;
|
|
36
14
|
onToggleCollapse?: () => void;
|
|
15
|
+
defaultExpanded?: boolean;
|
|
37
16
|
};
|
|
38
17
|
|
|
39
18
|
export const GenericView = memo(function GenericView(props: GenericViewProps) {
|
|
40
|
-
const { data, selected = false, onContextMenu, previewHints, onToggleCollapse } = props;
|
|
41
|
-
|
|
42
|
-
const theme = useGraphTheme();
|
|
19
|
+
const { data, selected = false, onContextMenu, previewHints, onToggleCollapse, defaultExpanded } = props;
|
|
43
20
|
|
|
44
|
-
const color = useMemo(() =>
|
|
21
|
+
const color = useMemo(() => typeColor(data.type), [data.type]);
|
|
45
22
|
const hasChildren = data.hasChildren;
|
|
46
23
|
const isCollapsed = data.isCollapsed;
|
|
47
24
|
|
|
@@ -55,137 +32,70 @@ export const GenericView = memo(function GenericView(props: GenericViewProps) {
|
|
|
55
32
|
|
|
56
33
|
const status = useMemo(() => getStatus(data), [data]);
|
|
57
34
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const total = properties.filter((prop) => isDisplayablePreviewKey(prop.key)).length;
|
|
77
|
-
|
|
78
|
-
const facts: CardFact[] = fields.map((field) => ({
|
|
79
|
-
label: field.label,
|
|
80
|
-
value: field.value,
|
|
81
|
-
highlighted: field.isHighlighted ?? false,
|
|
82
|
-
}));
|
|
83
|
-
|
|
84
|
-
return { displayProperties: facts, hiddenPropertiesCount: Math.max(0, total - facts.length) };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const importantKeys = ["name", "title", "label", "description", "id"];
|
|
88
|
-
const important: typeof properties = [];
|
|
89
|
-
const other: typeof properties = [];
|
|
90
|
-
|
|
91
|
-
for (const prop of properties) {
|
|
92
|
-
const keyLower = prop.key.toLowerCase();
|
|
93
|
-
if (importantKeys.some((k) => keyLower.includes(k))) {
|
|
94
|
-
important.push(prop);
|
|
95
|
-
} else {
|
|
96
|
-
other.push(prop);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const maxProperties = 4;
|
|
101
|
-
const allDisplayed: CardFact[] = [...important, ...other]
|
|
102
|
-
.slice(0, maxProperties)
|
|
103
|
-
.map((prop) => ({ label: prop.label ?? prop.key, value: prop.value, highlighted: false }));
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
displayProperties: allDisplayed,
|
|
107
|
-
hiddenPropertiesCount: Math.max(0, important.length + other.length - maxProperties),
|
|
108
|
-
};
|
|
109
|
-
}, [labeledProperties, status, previewHints]);
|
|
35
|
+
const include = useCallback((property: NodeProperty) => !status || property.key !== status.key, [status]);
|
|
36
|
+
// The header badge shows the status, so an IRI-valued one must not come back as a relation row either.
|
|
37
|
+
const relations = useMemo(() => {
|
|
38
|
+
const statusIri = status ? data.properties.find((property) => property.key === status.key)?.iri : undefined;
|
|
39
|
+
return statusIri ? data.relations?.filter((relation) => relation.predicate !== statusIri) : data.relations;
|
|
40
|
+
}, [status, data.properties, data.relations]);
|
|
41
|
+
|
|
42
|
+
const { facts, previewCount } = useAttributeFacts({
|
|
43
|
+
properties: data.properties,
|
|
44
|
+
relations,
|
|
45
|
+
jsonLd: data.jsonLd,
|
|
46
|
+
title: data.label,
|
|
47
|
+
type: data.type,
|
|
48
|
+
prefixLabels: true,
|
|
49
|
+
previewHints,
|
|
50
|
+
include,
|
|
51
|
+
});
|
|
110
52
|
|
|
111
53
|
return (
|
|
112
54
|
<div
|
|
113
|
-
className=
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
borderWidth: 2,
|
|
118
|
-
borderStyle: "solid",
|
|
119
|
-
...(selected && { boxShadow: `0 0 0 2px ${theme.node.selectedRing}` }),
|
|
120
|
-
}}
|
|
55
|
+
className={cn(
|
|
56
|
+
"min-w-60 max-w-80 overflow-hidden rounded-md-v4 border border-muted-border bg-muted text-default-foreground transition-shadow duration-200",
|
|
57
|
+
selected && "ring-2 ring-active-border",
|
|
58
|
+
)}
|
|
121
59
|
onContextMenu={onContextMenu}
|
|
122
60
|
>
|
|
123
|
-
<div className="
|
|
124
|
-
<div className="flex items-center gap-2
|
|
61
|
+
<div className="flex items-center justify-between gap-2 border-b border-muted-border px-3 py-2">
|
|
62
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
125
63
|
{hasChildren && onToggleCollapse && (
|
|
126
64
|
<button
|
|
65
|
+
type="button"
|
|
127
66
|
onClick={handleToggleClick}
|
|
128
|
-
className=
|
|
129
|
-
"w-5 h-5 rounded flex items-center justify-center shrink-0",
|
|
130
|
-
"bg-muted",
|
|
131
|
-
"hover:bg-muted transition-all duration-200",
|
|
132
|
-
)}
|
|
133
|
-
style={{ color: theme.node.text }}
|
|
67
|
+
className="nodrag flex size-5 shrink-0 items-center justify-center rounded bg-accent text-muted-foreground transition-colors hover:text-default-foreground"
|
|
134
68
|
title={isCollapsed ? "Expand" : "Collapse"}
|
|
135
69
|
>
|
|
136
|
-
<ChevronRight className={cn("
|
|
70
|
+
<ChevronRight className={cn("size-3 transition-transform duration-200", !isCollapsed && "rotate-90")} />
|
|
137
71
|
</button>
|
|
138
72
|
)}
|
|
139
|
-
<
|
|
73
|
+
<span aria-hidden className="size-2 shrink-0 rounded-full" style={{ backgroundColor: color }} />
|
|
74
|
+
<div className="typography-small-medium truncate" title={data.label}>
|
|
140
75
|
{data.label}
|
|
141
76
|
</div>
|
|
142
77
|
</div>
|
|
143
|
-
<div className="flex items-center gap-1.5
|
|
78
|
+
<div className="flex shrink-0 items-center gap-1.5">
|
|
144
79
|
{status && (
|
|
145
|
-
<
|
|
146
|
-
className="px-1.5 py-0.5 rounded typography-tiny"
|
|
147
|
-
style={{ backgroundColor: getStatusStyle(status.value).bg, color: getStatusStyle(status.value).text }}
|
|
148
|
-
>
|
|
80
|
+
<Badge size="sm" variant={statusBadgeVariant(status.value)}>
|
|
149
81
|
{status.value.toLowerCase()}
|
|
150
|
-
</
|
|
82
|
+
</Badge>
|
|
151
83
|
)}
|
|
152
84
|
{hasChildren && isCollapsed && (
|
|
153
|
-
<
|
|
154
|
-
className="px-1.5 py-0.5 rounded typography-tiny text-primary-foreground"
|
|
155
|
-
style={{ backgroundColor: color }}
|
|
156
|
-
>
|
|
85
|
+
<Badge size="sm" variant="secondary">
|
|
157
86
|
+{data.childIds.length}
|
|
158
|
-
</
|
|
87
|
+
</Badge>
|
|
159
88
|
)}
|
|
160
89
|
</div>
|
|
161
90
|
</div>
|
|
162
91
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
<span
|
|
171
|
-
style={{
|
|
172
|
-
color: highlighted ? theme.node.selectedRing : theme.node.text,
|
|
173
|
-
fontWeight: highlighted ? 600 : undefined,
|
|
174
|
-
}}
|
|
175
|
-
className="truncate text-right tabular-nums"
|
|
176
|
-
title={value}
|
|
177
|
-
>
|
|
178
|
-
{value}
|
|
179
|
-
</span>
|
|
180
|
-
</div>
|
|
181
|
-
))}
|
|
182
|
-
{hiddenPropertiesCount > 0 && (
|
|
183
|
-
<div className="typography-tiny italic" style={{ color: theme.node.textMuted }}>
|
|
184
|
-
+{hiddenPropertiesCount} more
|
|
185
|
-
</div>
|
|
186
|
-
)}
|
|
187
|
-
</div>
|
|
188
|
-
)}
|
|
92
|
+
<AttributeList
|
|
93
|
+
facts={facts}
|
|
94
|
+
previewCount={previewCount}
|
|
95
|
+
defaultExpanded={defaultExpanded}
|
|
96
|
+
searchClassName="px-3"
|
|
97
|
+
bodyClassName="px-3 py-2"
|
|
98
|
+
/>
|
|
189
99
|
</div>
|
|
190
100
|
);
|
|
191
101
|
});
|
|
@@ -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;
|