Add default row/column for new boards and prevent removing last column.
Some checks are pending
Node.js CI / build (push) Waiting to run

- New boards now start with one row containing one column
- Hide remove column button when only one column remains in a row

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Mike Cao 2026-01-19 03:02:51 -08:00
parent 385bdd6734
commit 6367d94552
2 changed files with 26 additions and 15 deletions

View file

@ -1,6 +1,7 @@
'use client'; 'use client';
import { Loading, useToast } from '@umami/react-zen'; import { Loading, useToast } from '@umami/react-zen';
import { createContext, type ReactNode, useCallback, useEffect, useRef, useState } from 'react'; import { createContext, type ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { v4 as uuid } from 'uuid';
import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks'; import { useApi, useMessages, useModified, useNavigation } from '@/components/hooks';
import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery'; import { useBoardQuery } from '@/components/hooks/queries/useBoardQuery';
import type { Board, BoardParameters } from '@/lib/types'; import type { Board, BoardParameters } from '@/lib/types';
@ -17,11 +18,13 @@ export interface BoardContextValue {
export const BoardContext = createContext<BoardContextValue>(null); export const BoardContext = createContext<BoardContextValue>(null);
const defaultBoard: Partial<Board> = { const createDefaultBoard = (): Partial<Board> => ({
name: '', name: '',
description: '', description: '',
parameters: { rows: [] }, parameters: {
}; rows: [{ id: uuid(), columns: [{ id: uuid(), component: null }] }],
},
});
export function BoardProvider({ boardId, children }: { boardId?: string; children: ReactNode }) { export function BoardProvider({ boardId, children }: { boardId?: string; children: ReactNode }) {
const { data, isFetching, isLoading } = useBoardQuery(boardId); const { data, isFetching, isLoading } = useBoardQuery(boardId);
@ -31,7 +34,7 @@ export function BoardProvider({ boardId, children }: { boardId?: string; childre
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { router, renderUrl } = useNavigation(); const { router, renderUrl } = useNavigation();
const [board, setBoard] = useState<Partial<Board>>(data ?? defaultBoard); const [board, setBoard] = useState<Partial<Board>>(data ?? createDefaultBoard());
const layoutGetterRef = useRef<LayoutGetter | null>(null); const layoutGetterRef = useRef<LayoutGetter | null>(null);
const registerLayoutGetter = useCallback((getter: LayoutGetter) => { const registerLayoutGetter = useCallback((getter: LayoutGetter) => {

View file

@ -221,7 +221,11 @@ function BoardRow({
{columns?.map((column, index) => ( {columns?.map((column, index) => (
<Fragment key={column.id}> <Fragment key={column.id}>
<Panel id={column.id} minSize={MIN_COLUMN_WIDTH} defaultSize={column.size}> <Panel id={column.id} minSize={MIN_COLUMN_WIDTH} defaultSize={column.size}>
<BoardColumn {...column} onRemove={handleRemoveColumn} /> <BoardColumn
{...column}
onRemove={handleRemoveColumn}
canRemove={columns?.length > 1}
/>
</Panel> </Panel>
{index < columns?.length - 1 && <Separator />} {index < columns?.length - 1 && <Separator />}
</Fragment> </Fragment>
@ -276,10 +280,12 @@ function BoardColumn({
id, id,
component, component,
onRemove, onRemove,
canRemove = true,
}: { }: {
id: string; id: string;
component?: ReactElement; component?: ReactElement;
onRemove?: (id: string) => void; onRemove?: (id: string) => void;
canRemove?: boolean;
}) { }) {
const handleAddComponent = () => {}; const handleAddComponent = () => {};
@ -294,16 +300,18 @@ function BoardColumn({
backgroundColor="3" backgroundColor="3"
position="relative" position="relative"
> >
<Box position="absolute" top="10px" right="20px" zIndex={100}> {canRemove && (
<TooltipTrigger delay={0}> <Box position="absolute" top="10px" right="20px" zIndex={100}>
<Button variant="quiet" onPress={() => onRemove?.(id)}> <TooltipTrigger delay={0}>
<Icon size="sm"> <Button variant="quiet" onPress={() => onRemove?.(id)}>
<X /> <Icon size="sm">
</Icon> <X />
</Button> </Icon>
<Tooltip>Remove column</Tooltip> </Button>
</TooltipTrigger> <Tooltip>Remove column</Tooltip>
</Box> </TooltipTrigger>
</Box>
)}
<Button variant="outline" onPress={handleAddComponent}> <Button variant="outline" onPress={handleAddComponent}>
<Icon> <Icon>
<Plus /> <Plus />