Skip to content

Commit 22f654b

Browse files
committed
many fixes in UI
1 parent 9442938 commit 22f654b

File tree

7 files changed

+89
-152
lines changed

7 files changed

+89
-152
lines changed

src/app/dfSlice.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ let deleteChartsRoutine = (state: DataFormulatorState, chartIds: string[]) => {
144144

145145
state.focusedTableId = charts.find(c => c.id == focusedChartId)?.tableRef;
146146
}
147-
state.chartSynthesisInProgress = state.chartSynthesisInProgress.filter(s => chartIds.includes(s));
147+
state.chartSynthesisInProgress = state.chartSynthesisInProgress.filter(s => !chartIds.includes(s));
148148

149149
// update focusedChart and activeThreadChart
150150
state.charts = charts;

src/app/utils.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,6 @@ export const assembleVegaChart = (
462462
}
463463
}
464464

465-
466-
467465
return {...vgObj, data: {values: values}}
468466
}
469467

src/views/ConceptCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ let ConceptReApplyButton: FC<{field: FieldItem,
185185
<Button onClick={() => { setApplicationDialogOpen(false), setTableRowsPreview([]), setCodePreview("") }}>Cancel</Button>
186186
<Button onClick={() => {
187187
setApplicationDialogOpen(false),
188-
setTableRowsPreview([]),
188+
setTableRowsPreview([]),
189189
setCodePreview(""),
190190
handleApply()
191191
}}>Apply</Button>

src/views/ConceptShelf.tsx

Lines changed: 71 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
Button,
1616
Divider,
1717
IconButton,
18+
Collapse,
1819
} from '@mui/material';
1920

2021
import AddCircleIcon from '@mui/icons-material/AddCircle';
@@ -49,6 +50,7 @@ export const ConceptGroup: FC<{groupName: string, fields: FieldItem[]}> = functi
4950

5051
const focusedTableId = useSelector((state: DataFormulatorState) => state.focusedTableId);
5152
const tables = useSelector((state: DataFormulatorState) => state.tables);
53+
5254
const [expanded, setExpanded] = useState(false);
5355
const dispatch = useDispatch();
5456

@@ -65,6 +67,10 @@ export const ConceptGroup: FC<{groupName: string, fields: FieldItem[]}> = functi
6567
}
6668
}, [focusedTableId])
6769

70+
// Separate fields for display logic
71+
const displayFields = expanded ? fields : fields.slice(0, 6);
72+
const hasMoreFields = fields.length > 6;
73+
6874
return <Box>
6975
<Box sx={{display: "block", width: "100%"}}>
7076
<Divider orientation="horizontal" textAlign="left">
@@ -78,11 +84,11 @@ export const ConceptGroup: FC<{groupName: string, fields: FieldItem[]}> = functi
7884
<Typography component="h2" sx={{fontSize: "10px"}} color="text.secondary">
7985
{groupName}
8086
</Typography>
81-
{groupName != "new fields" && <Typography sx={{fontSize: "10px", ml: 1}} color="text.secondary">
87+
{fields.length > 6 && <Typography sx={{fontSize: "10px", ml: 1}} color="text.secondary">
8288
{expanded ? '▾' : '▸'}
8389
</Typography>}
8490
{groupName === "new fields" && (
85-
<Tooltip title="Clean unused concepts - Remove fields not referenced by any table">
91+
<Tooltip title="clean fields not referenced by any table">
8692
<IconButton
8793
size="small"
8894
onClick={(e) => {
@@ -95,63 +101,80 @@ export const ConceptGroup: FC<{groupName: string, fields: FieldItem[]}> = functi
95101
px: 0.5,
96102
py: 0.25,
97103
height: "16px",
98-
ml: 0
104+
ml: '0',
105+
'&:hover .cleaning-icon': {
106+
animation: 'spin 0.5s cubic-bezier(0.4, 0, 0.2, 1)',
107+
transform: 'rotate(360deg)'
108+
},
109+
'@keyframes spin': {
110+
'0%': {
111+
transform: 'rotate(0deg)'
112+
},
113+
'100%': {
114+
transform: 'rotate(360deg)'
115+
}
116+
}
99117
}}
100118
>
101-
<CleaningServicesIcon sx={{ fontSize: "10px !important" }} />
119+
<CleaningServicesIcon className="cleaning-icon" sx={{ fontSize: "10px !important" }} />
102120
</IconButton>
103121
</Tooltip>
104122
)}
105123
</Box>
106124
</Divider>
107125
</Box>
108-
<Box
109-
sx={{
110-
maxHeight: expanded ? 'auto' : '240px',
111-
overflow: 'hidden',
112-
transition: 'max-height 0.3s ease-in-out',
113-
width: '100%'
114-
}}
115-
>
116-
{fields.map((field) => (
126+
127+
{/* Always show first 6 fields */}
128+
<Box sx={{ width: '100%' }}>
129+
{displayFields.map((field) => (
117130
<ConceptCard key={`concept-card-${field.id}`} field={field} />
118131
))}
119-
{fields.length > 6 && !expanded && (
120-
<Box sx={{
121-
position: 'relative',
122-
height: '40px',
123-
'&::after': {
124-
content: '""',
125-
position: 'absolute',
126-
bottom: 0,
127-
left: 0,
128-
right: 0,
129-
height: '100%',
130-
background: 'linear-gradient(to bottom, transparent, white)'
131-
}
132-
}}>
133-
<ConceptCard field={fields[6]} />
134-
</Box>
135-
)}
136132
</Box>
137-
{fields.length > 6 && !expanded && (
138-
<Button
139-
onClick={() => setExpanded(!expanded)}
140-
sx={{
141-
fontSize: "10px",
142-
color: "text.secondary",
143-
pl: 2,
144-
py: 0.5,
145-
fontStyle: "italic",
146-
textTransform: 'none',
147-
'&:hover': {
148-
background: 'transparent',
149-
textDecoration: 'underline'
150-
}
151-
}}
152-
>
153-
{`... show all ${fields.length} ${groupName} fields ▾`}
154-
</Button>
133+
134+
{/* Collapsible section for additional fields */}
135+
{hasMoreFields && (
136+
<>
137+
<Collapse in={expanded} timeout={300}>
138+
<Box sx={{ width: '100%' }}>
139+
{fields.slice(6).map((field) => (
140+
<ConceptCard key={`concept-card-${field.id}`} field={field} />
141+
))}
142+
</Box>
143+
</Collapse>
144+
145+
{!expanded && (
146+
<Button
147+
onClick={() => setExpanded(true)}
148+
sx={{
149+
fontSize: "10px",
150+
color: "text.secondary",
151+
pl: 2,
152+
py: 0.5,
153+
fontStyle: "italic",
154+
textTransform: 'none',
155+
position: 'relative',
156+
width: '100%',
157+
justifyContent: 'flex-start',
158+
'&:hover': {
159+
background: 'transparent',
160+
textDecoration: 'underline'
161+
},
162+
'&::before': {
163+
content: '""',
164+
position: 'absolute',
165+
top: '-20px',
166+
left: 0,
167+
right: 0,
168+
height: '20px',
169+
background: 'linear-gradient(to bottom, transparent, white)',
170+
pointerEvents: 'none'
171+
}
172+
}}
173+
>
174+
{`... show all ${fields.length} ${groupName} fields ▾`}
175+
</Button>
176+
)}
177+
</>
155178
)}
156179
</Box>;
157180
}
@@ -161,40 +184,8 @@ export const ConceptShelf: FC<ConceptShelfProps> = function ConceptShelf() {
161184

162185
// reference to states
163186
const conceptShelfItems = useSelector((state: DataFormulatorState) => state.conceptShelfItems);
164-
const focusedTableId = useSelector((state: DataFormulatorState) => state.focusedTableId);
165187
const tables = useSelector((state: DataFormulatorState) => state.tables);
166-
const charts = useSelector((state: DataFormulatorState) => state.charts);
167188

168-
const dispatch = useDispatch();
169-
170-
useEffect(() => {
171-
let focusedTable = tables.find(t => t.id == focusedTableId);
172-
if (focusedTable) {
173-
let names = focusedTable.names;
174-
// let missingNames = names.filter(name => !conceptShelfItems.some(field => field.name == name));
175-
176-
// let conceptsToAdd = missingNames.map((name) => {
177-
// return {
178-
// id: `concept-${name}-${Date.now()}`, name: name, type: "auto" as Type,
179-
// description: "", source: "custom", tableRef: 'custom', temporary: true, domain: [],
180-
// } as FieldItem
181-
// })
182-
// dispatch(dfActions.addConceptItems(conceptsToAdd));
183-
184-
// let conceptIdsToDelete = conceptShelfItems.filter(field => field.temporary == true
185-
// && !charts.some(c => Object.values(c.encodingMap).some(enc => enc.fieldID == field.id))
186-
// && !names.includes(field.name)).map(field => field.id);
187-
188-
// // add and delete temporary fields
189-
// dispatch(dfActions.batchDeleteConceptItemByID(conceptIdsToDelete));
190-
191-
} else {
192-
if (tables.length > 0) {
193-
dispatch(dfActions.setFocusedTable(tables[0].id))
194-
}
195-
}
196-
}, [focusedTableId])
197-
198189
// group concepts based on types
199190
let conceptItemGroups = groupConceptItems(conceptShelfItems, tables);
200191
let groupNames = [...new Set(conceptItemGroups.map(g => g.group))]

src/views/DataThread.tsx

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -622,18 +622,18 @@ const MemoizedChartObject = memo<{
622622
className={"vega-thumbnail vega-thumbnail-box"}
623623
onClick={() => onChartClick(chart.id, table.id)}
624624
sx={{
625-
display: "flex", backgroundColor: "rgba(0,0,0,0.01)", position: 'relative',
625+
display: "flex", backgroundColor: "white", position: 'relative',
626626
flexDirection: "column"
627627
}}>
628628
{status == 'pending' ? <Box sx={{
629629
position: "absolute", height: "100%", width: "100%", zIndex: 20,
630-
backgroundColor: "rgba(243, 243, 243, 0.8)", display: "flex", alignItems: "center", cursor: "pointer"
630+
backgroundColor: "rgba(243, 243, 243, 0.8)" , display: "flex", alignItems: "center", cursor: "pointer"
631631
}}>
632632
<LinearProgress sx={{ width: "100%", height: "100%", opacity: 0.05 }} />
633633
</Box> : ''}
634634
<Box sx={{ display: "flex", flexDirection: "column", margin: "auto" }}>
635-
<Box sx={{ margin: "auto" }} >
636-
{generateChartSkeleton(chartTemplate?.icon, 48, 48)}
635+
<Box sx={{ margin: "auto", transform: chart.chartType == 'Table' ? "rotate(15deg)" : undefined }} >
636+
{generateChartSkeleton(chartTemplate?.icon, 48, 48, chart.chartType == 'Table' ? 1 : 0.5)}
637637
</Box>
638638
<Box className='data-thread-chart-card-action-button'
639639
sx={{ zIndex: 10, color: 'blue', position: "absolute", right: 1, background: 'rgba(255, 255, 255, 0.95)' }}>
@@ -735,16 +735,6 @@ export const DataThread: FC<{}> = function ({ }) {
735735
executeScroll();
736736
}, [threadDrawerOpen])
737737

738-
// Create stable callback functions using useCallback
739-
const handleChartClick = useCallback((chartId: string, tableId: string) => {
740-
dispatch(dfActions.setFocusedChart(chartId));
741-
dispatch(dfActions.setFocusedTable(tableId));
742-
}, [dispatch]);
743-
744-
const handleChartDelete = useCallback((chartId: string) => {
745-
dispatch(dfActions.deleteChartById(chartId));
746-
}, [dispatch]);
747-
748738
// Now use useMemo to memoize the chartElements array
749739
let chartElements = useMemo(() => {
750740
return charts.filter(c => c.source == "user").map((chart) => {
@@ -756,12 +746,15 @@ export const DataThread: FC<{}> = function ({ }) {
756746
table={table}
757747
conceptShelfItems={conceptShelfItems}
758748
status={status}
759-
onChartClick={handleChartClick}
760-
onDelete={handleChartDelete}
749+
onChartClick={() => {
750+
dispatch(dfActions.setFocusedChart(chart.id));
751+
dispatch(dfActions.setFocusedTable(table.id));
752+
}}
753+
onDelete={() => {dispatch(dfActions.deleteChartById(chart.id))}}
761754
/>;
762755
return { chartId: chart.id, tableId: table.id, element };
763756
});
764-
}, [charts, tables, conceptShelfItems, chartSynthesisInProgress, handleChartClick, handleChartDelete]);
757+
}, [charts, tables, conceptShelfItems, chartSynthesisInProgress]);
765758

766759
// anchors are considered leaf tables to simplify the view
767760
let leafTables = [...tables.filter(t => (t.anchored && t.derive)), ...tables.filter(t => !tables.some(t2 => t2.derive?.trigger.tableId == t.id))];
@@ -890,7 +883,6 @@ export const DataThread: FC<{}> = function ({ }) {
890883

891884
let jumpButtons = drawerOpen ? jumpButtonsDrawerOpen : jumpButtonDrawerClosed;
892885

893-
894886
let carousel = (
895887
<Box className="data-thread" sx={{ overflow: 'hidden', }}>
896888
<Box sx={{

src/views/EncodingShelfCard.tsx

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ let selectBaseTables = (activeFields: FieldItem[], currentTable: DictTable, tabl
8585

8686
export const TriggerCard: FC<{className?: string, trigger: Trigger, hideFields?: boolean, label?: string}> = function ({ label, className, trigger, hideFields }) {
8787

88-
const charts = useSelector((state: DataFormulatorState) => state.charts);
8988
let fieldItems = useSelector((state: DataFormulatorState) => state.conceptShelfItems);
9089

9190
const dispatch = useDispatch<AppDispatch>();
@@ -135,51 +134,7 @@ export const TriggerCard: FC<{className?: string, trigger: Trigger, hideFields?:
135134
<Stack direction="row" sx={{marginLeft: 1, marginRight: 'auto', fontSize: 12}} alignItems="center" gap={"2px"}>
136135
<PrecisionManufacturing sx={{color: 'darkgray', width: '14px', height: '14px'}} />
137136
<Box sx={{margin: '4px 8px 4px 2px', flex: 1}}>
138-
{hideFields ? "" : <Typography fontSize="inherit" sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center',
139-
color: 'rgba(0,0,0,0.7)', maxWidth: 'calc(100%)'}}>{encodingComp}</Typography>}
140-
<Typography fontSize="inherit" sx={{textAlign: 'center',
141-
color: 'rgba(0,0,0,0.7)', maxWidth: 'calc(100%)'}}>{prompt}</Typography>
142-
</Box>
143-
</Stack>
144-
</Card>
145-
</Box>
146-
}
147-
148-
export const MiniTriggerCard: FC<{className?: string, trigger: Trigger, hideFields?: boolean, label?: string}> = function ({ label, className, trigger, hideFields }) {
149-
150-
let fieldItems = useSelector((state: DataFormulatorState) => state.conceptShelfItems);
151-
152-
let encodingComp : any = ''
153-
let prompt = trigger.instruction ? `"${trigger.instruction}"` : "";
154-
155-
if (trigger.chart) {
156-
157-
let chart = trigger.chart;
158-
let encodingMap = chart?.encodingMap;
159-
160-
encodingComp = Object.entries(encodingMap)
161-
.filter(([channel, encoding]) => {
162-
return encoding.fieldID != undefined;
163-
})
164-
.map(([channel, encoding], index) => {
165-
let field = fieldItems.find(f => f.id == encoding.fieldID) as FieldItem;
166-
return [index > 0 ? '⨉' : '',
167-
<Chip
168-
key={`trigger-${channel}-${field.id}`}
169-
sx={{color:'inherit', maxWidth: '110px', marginLeft: "2px", height: 16, fontSize: 'inherit', borderRadius: '4px',
170-
border: '1px solid rgb(250 235 215)', background: 'rgb(250 235 215 / 70%)',
171-
'& .MuiChip-label': { paddingLeft: '6px', paddingRight: '6px' }}}
172-
label={`${field.name}`} />]
173-
})
174-
}
175-
176-
return <Box sx={{ }}>
177-
<Card className={`${className}`} variant="outlined"
178-
sx={{textTransform: "none", backgroundColor: 'rgba(255, 160, 122, 0.07)' }}
179-
>
180-
<Stack direction="row" sx={{ marginRight: 'auto', fontSize: 11}} alignItems="center" gap={"2px"}>
181-
<Box sx={{margin: '4px 2px 4px 2px', flex: 1}}>
182-
{hideFields ? "" : <Typography fontSize="inherit" sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center',
137+
{prompt != "" && hideFields ? "" : <Typography fontSize="inherit" sx={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'center',
183138
color: 'rgba(0,0,0,0.7)', maxWidth: 'calc(100%)'}}>{encodingComp}</Typography>}
184139
<Typography fontSize="inherit" sx={{textAlign: 'center',
185140
color: 'rgba(0,0,0,0.7)', maxWidth: 'calc(100%)'}}>{prompt}</Typography>

src/views/VisualizationView.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,11 @@ export interface VisPanelState {
9191
viewMode: "gallery" | "carousel";
9292
}
9393

94-
export let generateChartSkeleton = (iconPath: string | undefined, width: number = 160, height: number = 160) => (
94+
export let generateChartSkeleton = (iconPath: string | undefined, width: number = 160, height: number = 160, opacity: number = 0.5) => (
9595
<Box width={width} height={height} sx={{ display: "flex" }}>
9696
{iconPath == undefined ?
9797
<AddchartIcon sx={{ color: "lightgray", margin: "auto" }} /> :
98-
<Box width="100%" sx={{ display: "flex", opacity: 0.5 }}>
98+
<Box width="100%" sx={{ display: "flex", opacity: opacity }}>
9999
<img height={Math.min(64, height)} width={Math.min(64, width)}
100100
style={{ maxHeight: Math.min(height, Math.max(32, 0.5 * height)), maxWidth: Math.min(width, Math.max(32, 0.5 * width)), margin: "auto" }}
101101
src={iconPath} alt="" role="presentation" />
@@ -476,18 +476,19 @@ export const ChartEditorFC: FC<{}> = function ChartEditorFC({}) {
476476

477477
element = <Box id={id} key={`focused-chart`} ></Box>
478478

479-
let assembledChart = assembleVegaChart(chart.chartType, chart.encodingMap, conceptShelfItems, visTableRows, 48, true);
479+
let assembledChart = assembleVegaChart(chart.chartType, chart.encodingMap, conceptShelfItems, visTableRows, Math.min(config.defaultChartWidth * 2 / 20, 48), true);
480480

481481
assembledChart['resize'] = true;
482482
assembledChart['config'] = {
483483
"view": {
484484
"continuousWidth": config.defaultChartWidth,
485-
"continuousHeight": config.defaultChartHeight
485+
"continuousHeight": config.defaultChartHeight,
486486
}
487487
}
488488

489489
embed('#' + id, { ...assembledChart }, { actions: true, renderer: "svg" }).then(function (result) {
490490
// Access the Vega view instance (https://vega.github.io/vega/docs/api/view/) as result.view
491+
491492

492493
// the intermediate data used by vega-lite
493494
//let data_0 = (result.view as any)._runtime.data.data_0.values.value;

0 commit comments

Comments
 (0)