feat(segmentation): segment statistics, labelmap interpolation and segment bidirectional (#4865)

This commit is contained in:
Alireza authored and GitHub committed 2025-03-17 22:34:34 -04:00
1 parent 694f3e9611
commit ec79b5523e
73 files changed
+3603 -1563

No files matched your search

@@ -1,47 +1,132 @@
import React from 'react';
import { useSegmentationTableContext } from './SegmentationTableContext';
import { PanelSection } from '../PanelSection';
import { SegmentationHeader } from './SegmentationHeader';
import { SegmentationTable } from './SegmentationTable';
import {
useSegmentationTableContext,
SegmentationExpandedProvider,
useSegmentationExpanded,
} from './contexts';
import { Button } from '../Button';
import { Icons } from '../Icons/Icons';
import { DropdownMenu, DropdownMenuTrigger } from '../DropdownMenu';
import { Tooltip, TooltipTrigger, TooltipContent } from '../Tooltip/Tooltip';
export const SegmentationExpanded: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
const { data } = useSegmentationTableContext('SegmentationExpanded');
// Separate the Header component from other children
const headerComponent = React.Children.toArray(children).find(
child => React.isValidElement(child) && child.type === SegmentationTable.Header
);
const otherChildren = React.Children.toArray(children).filter(
child => !(React.isValidElement(child) && child.type === SegmentationTable.Header)
);
// The Header container component
const SegmentationExpandedHeader = ({ children }: { children: React.ReactNode }) => {
const { segmentation, isActive } = useSegmentationExpanded('SegmentationExpandedHeader');
const { onSegmentationClick } = useSegmentationTableContext('SegmentationExpandedHeader');
return (
<>
{data.map(segmentationInfo => (
<PanelSection key={segmentationInfo.segmentation.segmentationId}>
<PanelSection.Header className="border-input border-t-2 bg-transparent pl-1">
{headerComponent ? (
React.cloneElement(headerComponent as React.ReactElement, {
segmentation: segmentationInfo.segmentation,
representation: segmentationInfo.representation,
})
) : (
<SegmentationHeader segmentation={segmentationInfo.segmentation} />
)}
</PanelSection.Header>
<PanelSection.Content>
<div className="segmentation-expanded-section">
{React.Children.map(otherChildren, child =>
React.isValidElement(child)
? React.cloneElement(child, {
segmentation: segmentationInfo.segmentation,
})
: child
)}
</div>
</PanelSection.Content>
</PanelSection>
))}
</>
<PanelSection.Header
className={`border-input border-t-2 bg-transparent pl-1 ${isActive ? 'border-primary' : ''} py-0`}
onClick={e => {
e.stopPropagation();
onSegmentationClick(segmentation.segmentationId);
}}
>
<div className="text-foreground flex h-8 w-full items-center">{children}</div>
</PanelSection.Header>
);
};
// Dropdown menu component - specifically for dropdown menu content
const SegmentationExpandedDropdownMenu = ({ children }: { children: React.ReactNode }) => {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="icon"
className="ml-1"
onClick={e => e.stopPropagation()}
>
<Icons.More />
</Button>
</DropdownMenuTrigger>
{children}
</DropdownMenu>
);
};
// Label component - for displaying the segmentation label
const SegmentationExpandedLabel = () => {
const { segmentation } = useSegmentationExpanded('SegmentationExpandedLabel');
return <div className="pl-1.5">{segmentation.label}</div>;
};
// Info component - for the info tooltip
const SegmentationExpandedInfo = () => {
const { segmentation } = useSegmentationExpanded('SegmentationExpandedInfo');
return (
<div className="ml-auto mr-1">
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
>
<Icons.Info className="h-6 w-6" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{segmentation.cachedStats?.info}</p>
</TooltipContent>
</Tooltip>
</div>
);
};
// Content component
const SegmentationExpandedContent = ({ children }: { children: React.ReactNode }) => {
return (
<PanelSection.Content className="py-0">
<div className="segmentation-expanded-section">{children}</div>
</PanelSection.Content>
);
};
// Main compound component
const SegmentationExpandedRoot = ({ children }) => {
const { data, activeSegmentationId, onSegmentationClick, mode } =
useSegmentationTableContext('SegmentationExpanded');
// Check if we should render based on mode
if (mode !== 'expanded' || !data || data.length === 0) {
return null;
}
return (
<div className="space-y-0">
{data.map(segmentationInfo => {
const isActive = segmentationInfo.segmentation.segmentationId === activeSegmentationId;
return (
<PanelSection
key={segmentationInfo.segmentation.segmentationId}
className="mb-0"
>
<SegmentationExpandedProvider
segmentation={segmentationInfo.segmentation}
representation={segmentationInfo.representation}
isActive={isActive}
onSegmentationClick={onSegmentationClick}
>
{children}
</SegmentationExpandedProvider>
</PanelSection>
);
})}
</div>
);
};
const SegmentationExpanded = Object.assign(SegmentationExpandedRoot, {
Header: SegmentationExpandedHeader,
DropdownMenu: SegmentationExpandedDropdownMenu,
Label: SegmentationExpandedLabel,
Info: SegmentationExpandedInfo,
Content: SegmentationExpandedContent,
});
export { SegmentationExpanded };