Cross-Source Enrichment Review

v0.5.0

Full-page cross-source enrichment review block with tag entities, clusters, relationships, and source connection map.

View as Markdown

Preview

Open full page ↗

Install & usage

npx shadcn@latest add @signalos/cross-source-01

Pulls the page source plus its widget dependencies (@signalos/tokens, @signalos/utils, @signalos/button, @signalos/badge, @signalos/form-dialog, @signalos/select, @signalos/checkbox, @signalos/input, @signalos/label, @signalos/tooltip, @signalos/split-panel, @signalos/page-header, @signalos/textarea, @signalos/dialog) into your app - you own the copy. Requires access.

usage
// after: npx shadcn@latest add @signalos/cross-source-01
// mount the pulled page in a route, e.g. src/app/semantics-details/page.tsx
import CrossSourceReview from "@/components/blocks/cross-source-01/CrossSource"

export default function Page() {
  return <CrossSourceReview />
}

Props

CrossSourceReviewProps

PropTypeDefaultDescription
titlestring | undefined-Title shown in the page header.
connectorIdsstring[] | undefined-Source connector identifiers.
relationshipsCrossSourceRelationship[] | undefined-Cross-source relationships to review.
flatTagEntitiesFlatTagEntry[] | undefined-Flat list of tag entities to review.
allClustersClustersWithConnector[] | undefined-All clusters (with connector id attached).
allAvailableTagsstring[] | undefined-All available tag names for dropdowns.
allClusterEntitiesstring[] | undefined-All cluster entity names.
entityClusterMapRecord<string, string> | undefined-Map from entity name to its cluster tag.
catalogTablesRecord<string, string[]> | undefined-Available tables per connector for relationship editing.
catalogColumnsRecord<string, string[]> | undefined-Available columns per connector.table for relationship editing.
isConfirmedboolean | undefined-Whether this stage has already been confirmed.
stageActionsReactNode-Optional action buttons (e.g. Rerun, Reset) rendered in the header.
isSubmittingboolean | undefined-Whether a submit is in progress.
errorMessagestring | undefined-Error message to show in the banner.
activeTabReviewTab | undefined-Active review tab.
relDecisionsRecord<number, RelDecision> | undefined-Per-relationship decision map.
selectedRelIdxnumber | null | undefined-Index of the selected relationship, or null.
deletedRelIndicesSet<number> | undefined-Set of relationship indices marked for deletion.
isEditingRelboolean | undefined-Whether the selected relationship is being edited.
relEditFormEditRelForm | undefined-Current relationship edit form values.
tagDecisionsRecord<number, TagDecision> | undefined-Per-tag decision map.
selectedTagIdxnumber | undefined-Index of the selected tag entity.
deletedTagIndicesSet<number> | undefined-Set of tag indices marked for deletion.
clusterEditsRecord<number, ClusterEditValue> | undefined-Per-cluster edit map.
editingClusterIdxnumber | null | undefined-Index of the cluster currently being edited.
clusterDialogOpenboolean | undefined-Whether the cluster edit dialog is open.
clusterEditStateClusterEditState | undefined-Current cluster edit state.
displayRelationshipsCrossSourceRelationship[] | undefined-Derived display relationships (with edits applied).
changeSummariesRecord<number, string[]> | undefined-Per-relationship change summaries.
sourceStatsRecord<string, { tables: Set<string>; relCount: number; }> | undefined-Source stats for the connection map.
totalFlaggednumber | undefined-Total number of flagged items.
editFromTablesstring[] | undefined-Derived tables for the from-side edit selects.
editToTablesstring[] | undefined-Derived tables for the to-side edit selects.
editFromColsstring[] | undefined-Derived columns for the from-side edit selects.
editToColsstring[] | undefined-Derived columns for the to-side edit selects.
editHasChangesboolean | undefined-Whether the edit form has unsaved changes.
editIsFormValidboolean | undefined-Whether the edit form is valid for saving.
onTabChange((tab: ReviewTab) => void) | undefined-Fired when the active tab changes.
onSubmit((action: "confirm") => void) | undefined-Fired when the user clicks submit.
onDismissError(() => void) | undefined-Fired when the user dismisses the error banner.
onSelectRel((idx: number) => void) | undefined-Fired when a relationship is selected.
onAcceptRel((idx: number) => void) | undefined-Fired when a relationship is accepted.
onStartEditing(() => void) | undefined-Fired when the edit mode starts.
onCancelEditing(() => void) | undefined-Fired when the edit mode is cancelled.
onSaveRelEdit(() => void) | undefined-Fired when the rel edit is saved.
onEditFromSourceChange((v: string) => void) | undefined-Fired when the edit from-source changes.
onEditFromTableChange((v: string) => void) | undefined-Fired when the edit from-table changes.
onEditFromColumnChange((v: string) => void) | undefined-Fired when the edit from-column changes.
onEditToSourceChange((v: string) => void) | undefined-Fired when the edit to-source changes.
onEditToTableChange((v: string) => void) | undefined-Fired when the edit to-table changes.
onEditToColumnChange((v: string) => void) | undefined-Fired when the edit to-column changes.
onEditRelTypeChange((v: RelationshipType) => void) | undefined-Fired when the edit rel-type changes.
onEditExplanationChange((v: string) => void) | undefined-Fired when the edit explanation changes.
onToggleDeleteRel((idx: number) => void) | undefined-Fired when a rel is toggled for deletion.
onSelectTag((idx: number) => void) | undefined-Fired when a tag is selected.
onSetTagDecision((gi: number, status: "accepted" | "flagged") => void) | undefined-Fired when a tag decision changes.
onUpdateTagEdit((gi: number, field: "tags" | "primary_tag", value: string | string[]) => void) | undefined-Fired when a tag edit field changes.
onToggleDeleteTag((gi: number) => void) | undefined-Fired when a tag is toggled for deletion.
onOpenEditCluster((idx: number) => void) | undefined-Fired when the cluster edit dialog is opened.
onSetClusterDialogOpen((open: boolean) => void) | undefined-Fired when the cluster dialog open state changes.
onSetClusterEditState((state: ClusterEditState) => void) | undefined-Fired when the cluster edit state changes.
onSaveClusterEdit((idx: number, state: ClusterEditState) => void) | undefined-Fired when a cluster edit is saved.
onUndoClusterEdit((idx: number) => void) | undefined-Fired when a cluster edit is undone.
addRelDialogOpenboolean | undefined-Whether the add-relationship dialog is open.
onSetAddRelDialogOpen((open: boolean) => void) | undefined-Fired when the add-relationship dialog open state changes.
isAddRelSubmittingboolean | undefined-Whether the add-relationship dialog is submitting.
addRelErrorMessagestring | null | undefined-Error message shown inside the add-relationship dialog.
addRelFormCrossSourceRelAddFormState | undefined-Controlled form values for the add-relationship dialog.
addRelFormErrorsCrossSourceRelAddFormErrors | undefined-Validation errors for the add-relationship dialog.
onAddRelFormChange(<K extends keyof CrossSourceRelAddFormState>(field: K, value: CrossSourceRelAddFormState[K]) => void) | undefined-Called when a field in the add-relationship form changes.
onAddRelFormErrorsChange((errors: CrossSourceRelAddFormErrors) => void) | undefined-Called when the add-relationship form errors change.
onAddRelSubmit((values: CrossSourceRelAddValues) => void | Promise<void>) | undefined-Fired when the add-relationship form is submitted.
addClusterDialogOpenboolean | undefined-Whether the add-cluster dialog is open.
onSetAddClusterDialogOpen((open: boolean) => void) | undefined-Fired when the add-cluster dialog open state changes.
isAddClusterSubmittingboolean | undefined-Whether the add-cluster dialog is submitting.
addClusterErrorMessagestring | null | undefined-Error message shown inside the add-cluster dialog.
addClusterFormClusterAddFormState | undefined-Controlled form values for the add-cluster dialog.
addClusterFormErrorsClusterAddFormErrors | undefined-Validation errors for the add-cluster dialog.
onAddClusterFormChange(<K extends keyof ClusterAddFormState>(field: K, value: ClusterAddFormState[K]) => void) | undefined-Called when a field in the add-cluster form changes.
onAddClusterFormErrorsChange((errors: ClusterAddFormErrors) => void) | undefined-Called when the add-cluster form errors change.
onAddClusterSubmit((values: ClusterAddValues) => void | Promise<void>) | undefined-Fired when the add-cluster form is submitted.
addTagEntityDialogOpenboolean | undefined-Whether the add-tag-entity dialog is open.
onSetAddTagEntityDialogOpen((open: boolean) => void) | undefined-Fired when the add-tag-entity dialog open state changes.
isAddTagEntitySubmittingboolean | undefined-Whether the add-tag-entity dialog is submitting.
addTagEntityErrorMessagestring | null | undefined-Error message shown inside the add-tag-entity dialog.
addTagEntityFormTagEntityAddFormState | undefined-Controlled form values for the add-tag-entity dialog.
addTagEntityFormErrorsTagEntityAddFormErrors | undefined-Validation errors for the add-tag-entity dialog.
onAddTagEntityFormChange(<K extends keyof TagEntityAddFormState>(field: K, value: TagEntityAddFormState[K]) => void) | undefined-Called when a field in the add-tag-entity form changes.
onAddTagEntityFormErrorsChange((errors: TagEntityAddFormErrors) => void) | undefined-Called when the add-tag-entity form errors change.
onAddTagEntitySubmit((values: TagEntityAddValues) => void | Promise<void>) | undefined-Fired when the add-tag-entity form is submitted.
classNamestring | undefined-
data-testidstring | undefined-Test identifier rendered as `data-testid` on the root element.

CrossSourceRelationship

PropTypeDefaultDescription
from_table*string-
from_column*string-
from_connector_id*string-
to_table*string-
to_column*string-
to_connector_id*string-
relationship_type*RelationshipType-
confidence*number-
detection_method*string-
explanationstring | undefined-
review_originstring | undefined-

CrossSourceReviewItem

PropTypeDefaultDescription
index*number-
status*"accepted" | "flagged" | "deleted"-
feedback*string-
edits*Partial<CrossSourceRelationship>-

RelDecision

PropTypeDefaultDescription
status*"accepted" | "flagged"-
feedback*string-
edits*Partial<CrossSourceRelationship>-

TagDecision

PropTypeDefaultDescription
status*"accepted" | "flagged"-
feedback*string-
edits*{ primary_tag?: string | undefined; tags?: string[] | undefined; }-
connectorId*string-
localIndex*number-

TagEntityMetadata

PropTypeDefaultDescription
reasoningstring | undefined-
column_countnumber | undefined-
business_purposestring | undefined-
relationships_summarystring | undefined-
definitionstring | undefined-
mapped_entitystring | undefined-
domain_contextstring | undefined-

TagEntity

PropTypeDefaultDescription
entity_id*string-
entity_name*string-
entity_type*string-
tags*string[]-
primary_tag*string-
connector_id*string-
metadataTagEntityMetadata | undefined-
review_originstring | undefined-

TagsArtifact

PropTypeDefaultDescription
all_tags*string[]-
entities*TagEntity[]-
connector_id*string-
total_entities*number-

GraphNode

PropTypeDefaultDescription
label*string-
node_idstring | undefined-
tags*string[]-
primary_tag*string-
connector_id*string-
metadataTagEntityMetadata | undefined-

GraphCluster

PropTypeDefaultDescription
tag*string-
nodes*GraphNode[]-
node_count*number-
edge_count*number-
review_originstring | undefined-

GraphArtifact

PropTypeDefaultDescription
clusters*GraphCluster[]-
total_nodes*number-
total_edges*number-
total_clusters*number-
connector_id*string-
cross_cluster_edgesunknown[] | undefined-

TagReviewItem

PropTypeDefaultDescription
index*number-
status*"accepted" | "flagged" | "deleted"-
feedback*string-
edits*{ primary_tag?: string | undefined; tags?: string[] | undefined; }-
connector_id*string-
local_index*number-

ClusterReviewItem

PropTypeDefaultDescription
index*number-
status*"accepted" | "flagged" | "deleted"-
edits*{ tag?: string | undefined; entities?: string[] | undefined; }-
connector_id*string-

CrossSourceItemEdits

PropTypeDefaultDescription
from_connector_id*string-
from_table*string-
from_column*string-
to_connector_id*string-
to_table*string-
to_column*string-
relationship_type*RelationshipType-
explanationstring | undefined-

CrossSourceTagItemEdits

PropTypeDefaultDescription
tag*string-
entity_names*string[]-

CrossSourceClusterItemEdits

PropTypeDefaultDescription
cluster_tag*string-
entity_names*string[]-

AddCrossSourceItemResponse

PropTypeDefaultDescription
statusstring | undefined-
indexnumber | undefined-
itemCrossSourceRelationship | undefined-
tagstring | undefined-
cluster_tagstring | undefined-
affectedstring[] | undefined-
soft_warningstring | undefined-

ItemEditPayload

PropTypeDefaultDescription
cluster_tagstring | undefined-
entity_namesstring[] | undefined-
tagstring | undefined-

SubmitCrossSourceEnrichedPayload

PropTypeDefaultDescription
action*"confirm" | "retry" | "add_item" | "add_cluster" | "add_tag"-
itemsCrossSourceReviewItem[] | undefined-
tag_itemsTagReviewItem[] | undefined-
cluster_itemsClusterReviewItem[] | undefined-
item_editsItemEditPayload | undefined-
feedbackstring | undefined-
connector_idstring | undefined-

SubmitCrossSourceReviewPayload

PropTypeDefaultDescription
action*"confirm" | "revise"-
items*CrossSourceReviewItem[]-

EditRelForm

PropTypeDefaultDescription
fromSource*string-
fromTable*string-
fromColumn*string-
toSource*string-
toTable*string-
toColumn*string-
relType*RelationshipType-
explanation*string-

RelEditChangeSummary

PropTypeDefaultDescription
changes*string[]-

ClusterEditValue

PropTypeDefaultDescription
status*"accepted" | "flagged"-
tagstring | undefined-
entitiesstring[] | undefined-

ClusterEditState

PropTypeDefaultDescription
tag*string-
newTagInput*string-
entities*string[]-

FlatTagEntry

PropTypeDefaultDescription
entity*TagEntity-
connectorId*string-
localIndex*number-

ClustersWithConnector

PropTypeDefaultDescription
_connectorId*string-
tag*string-
nodes*GraphNode[]-
node_count*number-
edge_count*number-
review_originstring | undefined-

CrossSourceFdeInput

PropTypeDefaultDescription
items*CrossSourceReviewItem[]-

ClusterAddValues

PropTypeDefaultDescription
connectorId*string-
cluster_tag*string-
entity_names*string[]-
notestring | undefined-

CrossSourceRelAddValues

PropTypeDefaultDescription
from_connector_id*string-
from_table*string-
from_column*string-
to_connector_id*string-
to_table*string-
to_column*string-
relationship_type*RelationshipType-
explanationstring | undefined-

TagEntityAddValues

PropTypeDefaultDescription
connectorId*string-
entity_name*string-
tags*string[]-
reasoningstring | undefined-

Supporting types

export type RelationshipType =
  | "references"
  | "has_many"
  | "belongs_to"
  | "many_to_many"
  | "one_to_one"
  | "measures"
  | "targets"
  | "sponsors"
  | "conducted_at"
  | "co_occurs"
  | "related_to"
export type ReviewTab = "tags" | "relationships"
export type AddCrossSourceItemPayload =
  | {
      action: "add_item"
      item_edits: CrossSourceItemEdits
      feedback?: string
      connector_id?: string
    }
  | {
      action: "add_tag"
      connector_id: string
      item_edits: CrossSourceTagItemEdits
      feedback?: string
    }
  | {
      action: "add_cluster"
      connector_id: string
      item_edits: CrossSourceClusterItemEdits
      feedback?: string
    }
export type CreateCrossSourceRelationshipPayload = CrossSourceRelationship

More Semantics Stages variants

Changelog

0.5.0

  • Decompose CrossSource.tsx into RelationshipsTab, TagsTab, and CrossSourcePageHeader subcomponents; move CrossSourceReviewProps interface to CrossSource.types.ts.
  • Add TagEntityAddDialog state (addTagEntityDialogOpen) and handleAddTagEntityDialogOpenChange handler to the preview.

0.4.9

  • Replace raw scale token classes with semantic tokens (text-text-error, bg-bg-success, border-border-warning, etc.) to respect client theme overrides.

0.4.8

  • Fix cross-item imports to use canonical @/components paths; add missing signalos.category to manifests.

0.4.7

  • CrossSource: rename data-testid from cross-source-add-tag-entity-button to cross-source-add-tag-button on the tags tab header button.
  • CrossSource: replace single Dismiss button in error banner with a Retry + Dismiss pair; Retry calls onSubmit?.("confirm").
  • CrossSource: swap availableTags={allAvailableTags}availableTags={allClusterEntities} when passing to TagEntityAddDialog.
  • CrossSource: reorder TagEntityAddDialog render before ClusterAddDialog in the dialog portal section.
  • ClusterAddDialog: replace FormDialog widget with raw Dialog/DialogContent/DialogHeader/DialogTitle/DialogDescription/DialogFooter.
  • CrossSource.types.ts: remove TagEntityAddFormState and TagEntityAddFormErrors interfaces (now defined inside the component file).

0.4.6

  • Add TagEntityAddDialog as a fully controlled component using FormDialog; wire into CrossSource with add-tag-entity props and header button on the tags tab.
  • Fix forbidden @/schemas import, internal state, and raw color-scale tokens in TagEntityAddDialog.
  • Add TagEntityAddFormState, TagEntityAddFormErrors, TagEntityAddValues to CrossSource.types.ts.

0.4.4

  • Replace raw shadcn Dialog in CrossSourceAddDialog and ClusterAddDialog with the reusable FormDialog widget; swap @signalos/dialog dependency for @signalos/form-dialog.

0.4.3

  • Fix file casing: rename Relationships.types.ts to match PascalCase import paths.

0.4.2

  • Lift ClusterAddDialog form state (form, errors) to controlled props; remove forbidden @/schemas and @/types imports, replace with inline validation.
  • Lift CrossSourceAddDialog form state (form, errors) to controlled props; remove forbidden @/schemas and @/types imports, replace with inline validation.
  • CrossSourceReview now receives addRelForm/addRelFormErrors/onAddRelFormChange/onAddRelFormErrorsChange and addClusterForm/addClusterFormErrors/onAddClusterFormChange/onAddClusterFormErrorsChange.

0.3.2

  • Content updates.

0.3.1

  • Replace grid grid-cols-1 lg:grid-cols-12 layout in both the tags and relationships tabs with SplitPanel widget.
  • Add @signalos/split-panel to registryDependencies.
  • Remove unused ArrowRightLeft icon import.

0.2.0

  • Refactor: lift all business logic, form state, and data transformations into CrossSourceReview (parent).
  • RelationshipDetailPanel is now fully presentational — EditRelationshipForm no longer owns state; all form values, derived column/table lists, validation flags, and handlers are passed as props from the parent.
  • isEditing toggle state moved to parent; panel receives it as a prop.
  • ClustersPanel: replaced three-setter "Edit" button logic with a single onOpenEditCluster(idx) callback; removed unused isNavigating prop.
  • RelQueueList: lifted inline change-summary IIFE to parent as changeSummaries (pre-computed Record<number, string[]>); component now renders only.
  • CrossSourceTabSwitcher: removed unused activeTab, hasTags, hasRelationships props.
  • CrossSource.types.ts: added EditRelForm, ClusterEditValue, ClusterEditState, FlatTagEntry, ClustersWithConnector exports; fixed casing import from Relationships.types.

0.1.0