Added basics of LCPLegend and more controls for blocks. Added boilerplate for lcp/line-graph

This commit is contained in:
Jeremy Rangel
2025-01-22 02:34:10 -08:00
parent dd4bd0caf5
commit 23944b0052
29 changed files with 24323 additions and 126 deletions

View File

@ -379,37 +379,51 @@ const LCPDataGrid = ({
event.preventDefault();
const target = event.target;
const rowCell = target.closest('.ag-cell');
const headerCell = target.closest('.ag-header-cell');
if (!rowCell) return;
const rect = rowCell.getBoundingClientRect();
const rowNode = gridRef.current.api.getRowNode(rowCell.parentElement.getAttribute('row-index'));
if (!rowNode || !rowNode.data || !rowNode.data.ID) return;
setContextMenu({
type: 'row',
position: { top: rect.bottom, left: rect.left },
rowIndex: rowNode.rowIndex,
totalRows: gridRef.current.api.getDisplayedRowCount()
});
if (rowCell) {
const rect = rowCell.getBoundingClientRect();
const rowNode = gridRef.current.api.getRowNode(rowCell.parentElement.getAttribute('row-index'));
if (!rowNode || !rowNode.data || !rowNode.data.ID) return;
setContextMenu({
type: 'row',
position: {
top: event.clientY,
left: event.clientX,
},
rowIndex: rowNode.rowIndex,
totalRows: gridRef.current.api.getDisplayedRowCount()
});
} else if (headerCell) {
const rect = headerCell.getBoundingClientRect();
const colId = headerCell.getAttribute('col-id');
if (!colId) return;
setContextMenu({
type: 'column',
position: {
top: event.clientY,
left: event.clientX,
},
colId: colId
});
}
}, []);
const handleRowAction = useCallback((action, rowIndex) => {
const handleRowAction = useCallback((action) => {
const newData = [...chartData];
const rowIndex = contextMenu.rowIndex;
// Create empty row with all existing columns
const emptyRow = { ID: generateId() };
if (chartData.length > 0) {
// Get all columns from existing data
const columns = Array.from(new Set(
chartData.flatMap(item => Object.keys(item))
));
// Initialize each column with an appropriate empty value
columns.forEach(col => {
if (col === 'ID') return; // Skip Id as it's already set
// Get a sample value to determine appropriate empty value
if (col === 'ID') return;
const sampleValue = chartData.find(item => item[col] !== undefined)?.[col];
switch (typeof sampleValue) {
@ -427,19 +441,59 @@ const LCPDataGrid = ({
switch (action) {
case 'add-above':
newData.splice(rowIndex - 1, 0, emptyRow);
break;
case 'add-below':
newData.splice(rowIndex, 0, emptyRow);
break;
case 'add-below':
newData.splice(rowIndex + 1, 0, emptyRow);
break;
case 'delete':
newData.splice(rowIndex - 1, 1);
newData.splice(rowIndex, 1);
break;
}
onDataChange(newData);
setContextMenu(null);
}, [chartData, onDataChange]);
}, [chartData, onDataChange, contextMenu]);
const handleColumnAction = useCallback((action) => {
if (!contextMenu || !contextMenu.colId) return;
const newData = [...chartData];
const colId = contextMenu.colId;
switch (action) {
case 'delete':
// Remove the column from all rows
newData.forEach(row => {
const { [colId]: removed, ...rest } = row;
Object.assign(row, rest);
});
break;
case 'add-left':
case 'add-right':
// Get all existing column names
const existingColumns = Object.keys(chartData[0] || {});
// Find the next available column number
let nextNumber = 1;
while (existingColumns.includes(`Column${nextNumber}`)) {
nextNumber++;
}
const newColId = `Column${nextNumber}`;
const insertIndex = columnDefs.findIndex(col => col.field === colId);
const finalIndex = action === 'add-right' ? insertIndex + 1 : insertIndex;
// Add the new column to all rows
newData.forEach(row => {
row[newColId] = '';
});
break;
}
onDataChange(newData);
setContextMenu(null);
}, [chartData, onDataChange, contextMenu, columnDefs]);
const handleCellValueChanged = useCallback((params) => {
if (!params.data || !params.data.ID) return;
@ -451,8 +505,15 @@ const LCPDataGrid = ({
onDataChange(newData);
}, [chartData, onDataChange]);
return (
<div className="ag-theme-alpine" style={{ height: '400px', width: '100%' }}>
<div
className="ag-theme-alpine"
style={{ height: '400px', width: '100%' }}
onContextMenu={handleContextMenu}
>
<AgGridReact
ref={gridRef}
rowData={rowData}
@ -472,24 +533,57 @@ const LCPDataGrid = ({
position="bottom left"
onClose={() => setContextMenu(null)}
anchorRect={{
top: contextMenu.mouseEvent.clientY,
left: contextMenu.mouseEvent.clientX,
top: contextMenu.position.top,
left: contextMenu.position.left,
width: 0,
height: 0,
}}
>
<div style={{ padding: '8px' }}>
<Button
variant="secondary"
onClick={() => {
const selectedRows = gridRef.current.api.getSelectedRows();
const newData = chartData.filter(row => !selectedRows.includes(row));
onDataChange(newData);
setContextMenu(null);
}}
>
{__('Delete Selected Rows', 'lcp-visualize')}
</Button>
<div style={{ padding: '8px', display: 'flex', flexDirection: 'column', gap: '4px' }}>
{contextMenu.type === 'row' && (
<>
<Button
variant="secondary"
onClick={() => handleRowAction('add-above')}
>
{__('Add Row Above', 'lcp-visualize')}
</Button>
<Button
variant="secondary"
onClick={() => handleRowAction('add-below')}
>
{__('Add Row Below', 'lcp-visualize')}
</Button>
<Button
variant="secondary"
onClick={() => handleRowAction('delete')}
>
{__('Delete Row', 'lcp-visualize')}
</Button>
</>
)}
{contextMenu.type === 'column' && (
<>
<Button
variant="secondary"
onClick={() => handleColumnAction('add-left')}
>
{__('Add Column Left', 'lcp-visualize')}
</Button>
<Button
variant="secondary"
onClick={() => handleColumnAction('add-right')}
>
{__('Add Column Right', 'lcp-visualize')}
</Button>
<Button
variant="secondary"
onClick={() => handleColumnAction('delete')}
>
{__('Delete Column', 'lcp-visualize')}
</Button>
</>
)}
</div>
</Popover>
)}