mirror of
https://github.com/umami-software/umami.git
synced 2026-02-04 04:37:11 +01:00
Add move row up/down functionality to board editor.
Rows can now be reordered using up/down buttons. Buttons are disabled at boundaries (up disabled on first row, down disabled on last row). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
d9f698ca42
commit
ff6575ff54
1 changed files with 113 additions and 35 deletions
|
|
@ -4,7 +4,7 @@ import { Fragment, type ReactElement } from 'react';
|
|||
import { Group, Panel, Separator } from 'react-resizable-panels';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { useBoard } from '@/components/hooks';
|
||||
import { Minus, Plus } from '@/components/icons';
|
||||
import { ChevronDown, Minus, Plus } from '@/components/icons';
|
||||
import type { BoardColumn as BoardColumnType } from '@/lib/types';
|
||||
|
||||
const CATALOG = {
|
||||
|
|
@ -14,6 +14,12 @@ const CATALOG = {
|
|||
},
|
||||
};
|
||||
|
||||
const MIN_HEIGHT = 300;
|
||||
const MAX_HEIGHT = 600;
|
||||
const MIN_WIDTH = 300;
|
||||
const MARGIN = 10;
|
||||
const MAX_COLUMNS = 4;
|
||||
|
||||
export function BoardBody() {
|
||||
const { board, updateBoard, saveBoard, isPending } = useBoard();
|
||||
|
||||
|
|
@ -31,7 +37,6 @@ export function BoardBody() {
|
|||
};
|
||||
|
||||
const handleRemoveRow = (id: string) => {
|
||||
console.log('Removing row', id);
|
||||
updateBoard({
|
||||
parameters: produce(board.parameters, draft => {
|
||||
if (!draft.rows) {
|
||||
|
|
@ -43,44 +48,90 @@ export function BoardBody() {
|
|||
});
|
||||
};
|
||||
|
||||
const handleMoveRowUp = (id: string) => {
|
||||
updateBoard({
|
||||
parameters: produce(board.parameters, draft => {
|
||||
if (!draft.rows) return;
|
||||
|
||||
const index = draft.rows.findIndex(row => row.id === id);
|
||||
if (index > 0) {
|
||||
const temp = draft.rows[index - 1];
|
||||
draft.rows[index - 1] = draft.rows[index];
|
||||
draft.rows[index] = temp;
|
||||
}
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const handleMoveRowDown = (id: string) => {
|
||||
updateBoard({
|
||||
parameters: produce(board.parameters, draft => {
|
||||
if (!draft.rows) return;
|
||||
|
||||
const index = draft.rows.findIndex(row => row.id === id);
|
||||
if (index < draft.rows.length - 1) {
|
||||
const temp = draft.rows[index + 1];
|
||||
draft.rows[index + 1] = draft.rows[index];
|
||||
draft.rows[index] = temp;
|
||||
}
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
const rows = board?.parameters?.rows ?? [];
|
||||
const minHeight = 300 * (rows.length || 1);
|
||||
const rowCount = (rows.length || 1) + 1;
|
||||
const minHeight = (MAX_HEIGHT + MARGIN) * rowCount;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Group orientation="vertical" style={{ minHeight }}>
|
||||
{rows.map((row, index) => (
|
||||
<Fragment key={row.id}>
|
||||
<Panel minSize={200}>
|
||||
<BoardRow {...row} rowId={row.id} onRemove={handleRemoveRow} />
|
||||
</Panel>
|
||||
{index < rows.length - 1 && <Separator />}
|
||||
</Fragment>
|
||||
))}
|
||||
</Group>
|
||||
<Row>
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button variant="outline" onPress={handleAddRow}>
|
||||
<Icon>
|
||||
<Plus />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="bottom">Add row</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Row>
|
||||
</>
|
||||
<Group orientation="vertical" style={{ minHeight }}>
|
||||
{rows.map((row, index) => (
|
||||
<Fragment key={row.id}>
|
||||
<Panel minSize={MIN_HEIGHT}>
|
||||
<BoardRow
|
||||
{...row}
|
||||
rowId={row.id}
|
||||
rowIndex={index}
|
||||
rowCount={rows.length}
|
||||
onRemove={handleRemoveRow}
|
||||
onMoveUp={handleMoveRowUp}
|
||||
onMoveDown={handleMoveRowDown}
|
||||
/>
|
||||
</Panel>
|
||||
{index < rows.length - 1 && <Separator />}
|
||||
</Fragment>
|
||||
))}
|
||||
<Panel>
|
||||
<Row padding="3">
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button variant="outline" onPress={handleAddRow}>
|
||||
<Icon>
|
||||
<Plus />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="bottom">Add row</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Row>
|
||||
</Panel>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
||||
function BoardRow({
|
||||
rowId,
|
||||
rowIndex,
|
||||
rowCount,
|
||||
columns,
|
||||
onRemove,
|
||||
onMoveUp,
|
||||
onMoveDown,
|
||||
}: {
|
||||
rowId: string;
|
||||
rowIndex: number;
|
||||
rowCount: number;
|
||||
columns: BoardColumnType[];
|
||||
onAddComponent?: () => void;
|
||||
onRemove?: (id: string) => void;
|
||||
onMoveUp?: (id: string) => void;
|
||||
onMoveDown?: (id: string) => void;
|
||||
}) {
|
||||
const { board, updateBoard } = useBoard();
|
||||
|
||||
|
|
@ -102,27 +153,54 @@ function BoardRow({
|
|||
<Group style={{ height: '100%' }}>
|
||||
{columns?.map((column, index) => (
|
||||
<Fragment key={column.id}>
|
||||
<Panel minSize={300}>
|
||||
<Panel minSize={MIN_HEIGHT}>
|
||||
<BoardColumn {...column} />
|
||||
</Panel>
|
||||
{index < columns.length - 1 && <Separator />}
|
||||
</Fragment>
|
||||
))}
|
||||
<Box alignSelf="center" padding="3">
|
||||
<Button variant="outline" onPress={handleAddColumn}>
|
||||
<Icon>
|
||||
<Plus />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Column alignSelf="center" padding="3" gap="1">
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button variant="outline" onPress={() => onMoveUp?.(rowId)} isDisabled={rowIndex === 0}>
|
||||
<Icon rotate={180}>
|
||||
<ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="top">Move row up</Tooltip>
|
||||
</TooltipTrigger>
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button
|
||||
variant="outline"
|
||||
onPress={handleAddColumn}
|
||||
isDisabled={columns.length >= MAX_COLUMNS}
|
||||
>
|
||||
<Icon>
|
||||
<Plus />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="left">Add column</Tooltip>
|
||||
</TooltipTrigger>
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button variant="outline" onPress={() => onRemove?.(rowId)}>
|
||||
<Icon>
|
||||
<Minus />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="bottom">Remove row</Tooltip>
|
||||
<Tooltip placement="left">Remove row</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Box>
|
||||
<TooltipTrigger delay={0}>
|
||||
<Button
|
||||
variant="outline"
|
||||
onPress={() => onMoveDown?.(rowId)}
|
||||
isDisabled={rowIndex === rowCount - 1}
|
||||
>
|
||||
<Icon>
|
||||
<ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Tooltip placement="bottom">Move row down</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Column>
|
||||
</Group>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue