()
| 77 | * Used by both EncodingShelfCard (chart-aware formulation) and ChartRecBox (NL-driven formulation). |
| 78 | */ |
| 79 | export function useFormulateData() { |
| 80 | const dispatch = useDispatch<AppDispatch>(); |
| 81 | const { t } = useTranslation(); |
| 82 | const tables = useSelector((state: DataFormulatorState) => state.tables); |
| 83 | const config = useSelector((state: DataFormulatorState) => state.config); |
| 84 | const conceptShelfItems = useSelector((state: DataFormulatorState) => state.conceptShelfItems); |
| 85 | const charts = useSelector(dfSelectors.getAllCharts); |
| 86 | const activeModel = useSelector(dfSelectors.getActiveModel); |
| 87 | |
| 88 | /** |
| 89 | * Resolve the actual chart that's rendered for a derived table. The |
| 90 | * `trigger.chart` saved on the table is just an "Auto" stub generated |
| 91 | * during the agent run — the chart the user actually sees lives in the |
| 92 | * Redux `charts` slice. Mirrors the lookup in `SimpleChartRecBox`. |
| 93 | */ |
| 94 | function resolveChartForTable(tableId: string) { |
| 95 | return charts.find(c => c.tableRef === tableId && c.source === 'trigger') |
| 96 | || charts.find(c => c.tableRef === tableId); |
| 97 | } |
| 98 | |
| 99 | /** Map a chart's encodingMap to `{ channel: fieldName }` (skips empties). */ |
| 100 | function chartEncodingsByName(chart: Chart | undefined): Record<string, string> { |
| 101 | if (!chart?.encodingMap) return {}; |
| 102 | return Object.fromEntries( |
| 103 | Object.entries(chart.encodingMap) |
| 104 | .filter(([, v]: [string, any]) => v?.fieldID) |
| 105 | .map(([k, v]: [string, any]) => { |
| 106 | const field = conceptShelfItems.find(f => f.id === v.fieldID); |
| 107 | return [k, field?.name || v.fieldID]; |
| 108 | }) |
| 109 | ); |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Build a rich focused thread from the current table's derivation chain. |
| 114 | * Each step includes: user question, display instruction, chart type + encodings, |
| 115 | * created table metadata, and agent summary. |
| 116 | */ |
| 117 | function buildFocusedThread(currentTable: DictTable): any[] { |
| 118 | if (!currentTable.derive || currentTable.anchored) return []; |
| 119 | const triggers = getTriggers(currentTable, tables); |
| 120 | return triggers.map(trigger => { |
| 121 | const resultTable = tables.find(t2 => t2.id === trigger.resultTableId); |
| 122 | const interaction = trigger.interaction || []; |
| 123 | const userPrompt = interaction.find(e => e.role === 'prompt')?.content; |
| 124 | const instruction = interaction.find(e => e.role === 'instruction'); |
| 125 | const summary = interaction.find(e => e.role === 'summary'); |
| 126 | // Resolve the actual rendered chart (not the trigger's "Auto" stub) |
| 127 | // so chart_type + encodings reflect what the user is looking at. |
| 128 | const resolvedChart = resolveChartForTable(trigger.resultTableId); |
| 129 | return { |
| 130 | user_question: userPrompt || instruction?.content || '', |
| 131 | display_instruction: instruction?.displayContent || instruction?.content || '', |
| 132 | agent_thinking: instruction?.plan, |
| 133 | agent_summary: summary?.content, |
| 134 | table_name: resultTable?.virtual?.tableId || trigger.resultTableId, |
| 135 | columns: resultTable?.names || [], |
| 136 | row_count: resultTable?.virtual?.rowCount ?? resultTable?.rows?.length ?? 0, |
no outgoing calls
no test coverage detected