({
threadIdx,
threadLabel,
isSplitThread = false,
hasContinuationBelow = false,
hideLabel = false,
leafTables,
chartElements,
usedIntermediateTableIds,
globalHighlightedTableIds,
focusedThreadLeafId,
sx
})
| 824 | focusedThreadLeafId?: string, // The leaf table ID of the thread containing the focused table |
| 825 | sx?: SxProps |
| 826 | }> = function ({ |
| 827 | threadIdx, |
| 828 | threadLabel, |
| 829 | isSplitThread = false, |
| 830 | hasContinuationBelow = false, |
| 831 | hideLabel = false, |
| 832 | leafTables, |
| 833 | chartElements, |
| 834 | usedIntermediateTableIds, |
| 835 | globalHighlightedTableIds, |
| 836 | focusedThreadLeafId, |
| 837 | sx |
| 838 | }) { |
| 839 | |
| 840 | let tables = useSelector((state: DataFormulatorState) => state.tables); |
| 841 | const activeWorkspace = useSelector((state: DataFormulatorState) => state.activeWorkspace); |
| 842 | const { t } = useTranslation(); |
| 843 | const { manualRefresh } = useDataRefresh(); |
| 844 | const tableById = useMemo(() => new Map(tables.map(t => [t.id, t])), [tables]); |
| 845 | |
| 846 | let leafTableIds = leafTables.map(lt => lt.id); |
| 847 | // Thread is highlighted only if this thread's leaf tables include the focused thread's leaf |
| 848 | const threadHighlighted = focusedThreadLeafId |
| 849 | ? leafTableIds.includes(focusedThreadLeafId) |
| 850 | : false; |
| 851 | // Ancestor thread: not the focused thread, but *owns* some highlighted tables |
| 852 | // (tables that only appear as used/shared references don't count) |
| 853 | const isAncestorThread = !threadHighlighted && globalHighlightedTableIds.length > 0 |
| 854 | && leafTables.some(lt => { |
| 855 | const trigs = getTriggers(lt, tables); |
| 856 | const chainIds = [...trigs.map(tp => tp.tableId), lt.id]; |
| 857 | const ownedIds = chainIds.filter(id => !usedIntermediateTableIds.includes(id)); |
| 858 | return ownedIds.some(id => globalHighlightedTableIds.includes(id)); |
| 859 | }); |
| 860 | const shouldHighlightThread = threadHighlighted || isAncestorThread; |
| 861 | let parentTableId = leafTables[0].derive?.trigger.tableId || undefined; |
| 862 | let parentTable = (parentTableId ? tableById.get(parentTableId) : undefined) as DictTable; |
| 863 | |
| 864 | let charts = useSelector(dfSelectors.getAllCharts); |
| 865 | let focusedId = useSelector((state: DataFormulatorState) => state.focusedId); |
| 866 | let focusedChartId = focusedId?.type === 'chart' ? focusedId.chartId : undefined; |
| 867 | let focusedTableId = useMemo(() => { |
| 868 | if (!focusedId) return undefined; |
| 869 | if (focusedId.type === 'table') return focusedId.tableId; |
| 870 | if (focusedId.type === 'chart') { |
| 871 | const chart = charts.find(c => c.id === focusedId.chartId); |
| 872 | return chart?.tableRef; |
| 873 | } |
| 874 | return undefined; |
| 875 | }, [focusedId, charts]); |
| 876 | let draftNodes = useSelector((state: DataFormulatorState) => state.draftNodes); |
| 877 | let generatedReports = useSelector(dfSelectors.getAllGeneratedReports); |
| 878 | |
| 879 | // Build a map from tableId → reports triggered from that table |
| 880 | const reportsByTriggerTable = useMemo(() => { |
| 881 | const map = new Map<string, GeneratedReport[]>(); |
| 882 | for (const report of generatedReports) { |
| 883 | const triggerId = report.triggerTableId; |
nothing calls this directly
no test coverage detected