edit table from canvas

This commit is contained in:
Guy Ben-Aharon
2024-08-21 10:05:37 +03:00
parent 4ede0f3117
commit d4da127de6
7 changed files with 88 additions and 21 deletions

View File

@@ -0,0 +1,18 @@
import { emptyFn } from '@/lib/utils';
import { createContext } from 'react';
export type SidebarSection = 'tables' | 'relationships';
export interface LayoutContext {
openedTableInSidebar: string | undefined;
openTableFromSidebar: (tableId: string) => void;
selectedSidebarSection: SidebarSection;
selectSidebarSection: (section: SidebarSection) => void;
}
export const layoutContext = createContext<LayoutContext>({
openedTableInSidebar: undefined,
selectedSidebarSection: 'tables',
selectSidebarSection: emptyFn,
openTableFromSidebar: emptyFn,
});

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { layoutContext, SidebarSection } from './layout-context';
export const LayoutProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const [openedTableInSidebar, setOpenedTableInSidebar] = React.useState<
string | undefined
>();
const [selectedSidebarSection, setSelectedSidebarSection] =
React.useState<SidebarSection>('tables');
return (
<layoutContext.Provider
value={{
openedTableInSidebar,
selectedSidebarSection,
openTableFromSidebar: setOpenedTableInSidebar,
selectSidebarSection: setSelectedSidebarSection,
}}
>
{children}
</layoutContext.Provider>
);
};

4
src/hooks/use-layout.ts Normal file
View File

@@ -0,0 +1,4 @@
import { useContext } from 'react';
import { layoutContext } from '@/context/layout-context/layout-context';
export const useLayout = () => useContext(layoutContext);

View File

@@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import { NodeProps, Node } from '@xyflow/react'; import { NodeProps, Node } from '@xyflow/react';
import { Button } from '@/components/button/button'; import { Button } from '@/components/button/button';
import { Ellipsis, Table2 } from 'lucide-react'; import { Pencil, Table2 } from 'lucide-react';
import { Label } from '@/components/label/label'; import { Label } from '@/components/label/label';
import { DBTable } from '@/lib/domain/db-table'; import { DBTable } from '@/lib/domain/db-table';
import { TableNodeField } from './table-node-field'; import { TableNodeField } from './table-node-field';
import { useLayout } from '@/hooks/use-layout';
export type TableNodeType = Node< export type TableNodeType = Node<
{ {
@@ -19,8 +20,14 @@ export const TableNode: React.FC<NodeProps<TableNodeType>> = ({
id, id,
data: { table }, data: { table },
}) => { }) => {
const { openTableFromSidebar, selectSidebarSection } = useLayout();
const focused = !!selected && !dragging; const focused = !!selected && !dragging;
const openTableInEditor = () => {
selectSidebarSection('tables');
openTableFromSidebar(table.id);
};
return ( return (
<div <div
className={`flex flex-col w-56 bg-background border ${selected ? 'border-slate-400' : ''} rounded-lg shadow-sm`} className={`flex flex-col w-56 bg-background border ${selected ? 'border-slate-400' : ''} rounded-lg shadow-sm`}
@@ -38,8 +45,9 @@ export const TableNode: React.FC<NodeProps<TableNodeType>> = ({
<Button <Button
variant="ghost" variant="ghost"
className="hover:bg-primary-foreground p-0 w-6 h-6 text-slate-500 hover:text-slate-700" className="hover:bg-primary-foreground p-0 w-6 h-6 text-slate-500 hover:text-slate-700"
onClick={openTableInEditor}
> >
<Ellipsis className="h-4 w-4" /> <Pencil className="h-4 w-4" />
</Button> </Button>
</div> </div>
</div> </div>

View File

@@ -9,17 +9,22 @@ import {
} from '@/components/select/select'; } from '@/components/select/select';
import { TablesSection } from './tables-section/tables-section'; import { TablesSection } from './tables-section/tables-section';
import { RelationshipsSection } from './relationships-section/relationships-section'; import { RelationshipsSection } from './relationships-section/relationships-section';
import { useLayout } from '@/hooks/use-layout';
import { SidebarSection } from '@/context/layout-context/layout-context';
export interface SidePanelProps {} export interface SidePanelProps {}
export const SidePanel: React.FC<SidePanelProps> = () => { export const SidePanel: React.FC<SidePanelProps> = () => {
const [selected, setSelected] = React.useState('tables'); // const [selected, setSelected] = React.useState('tables');
const { selectSidebarSection, selectedSidebarSection } = useLayout();
return ( return (
<aside className="flex h-full flex-col overflow-hidden"> <aside className="flex h-full flex-col overflow-hidden">
<div className="flex justify-center border-b pt-0.5"> <div className="flex justify-center border-b pt-0.5">
<Select <Select
value={selected} value={selectedSidebarSection}
onValueChange={(value) => setSelected(value)} onValueChange={(value) =>
selectSidebarSection(value as SidebarSection)
}
> >
<SelectTrigger className="border-none rounded-none shadow-none focus:border-transparent focus:ring-0 hover:underline hover:bg-secondary font-semibold"> <SelectTrigger className="border-none rounded-none shadow-none focus:border-transparent focus:ring-0 hover:underline hover:bg-secondary font-semibold">
<SelectValue /> <SelectValue />
@@ -34,7 +39,7 @@ export const SidePanel: React.FC<SidePanelProps> = () => {
</SelectContent> </SelectContent>
</Select> </Select>
</div> </div>
{selected === 'tables' ? ( {selectedSidebarSection === 'tables' ? (
<TablesSection /> <TablesSection />
) : ( ) : (
<RelationshipsSection /> <RelationshipsSection />

View File

@@ -2,17 +2,21 @@ import React from 'react';
import { Accordion } from '@/components/accordion/accordion'; import { Accordion } from '@/components/accordion/accordion';
import { TableListItem } from './table-list-item/table-list-item'; import { TableListItem } from './table-list-item/table-list-item';
import { DBTable } from '@/lib/domain/db-table'; import { DBTable } from '@/lib/domain/db-table';
import { useLayout } from '@/hooks/use-layout';
export interface TableListProps { export interface TableListProps {
tables: DBTable[]; tables: DBTable[];
} }
export const TableList: React.FC<TableListProps> = ({ tables }) => { export const TableList: React.FC<TableListProps> = ({ tables }) => {
const { openTableFromSidebar, openedTableInSidebar } = useLayout();
return ( return (
<Accordion <Accordion
type="single" type="single"
collapsible collapsible
className="flex flex-col w-full gap-1" className="flex flex-col w-full gap-1"
value={openedTableInSidebar}
onValueChange={openTableFromSidebar}
> >
{tables.map((table) => ( {tables.map((table) => (
<TableListItem key={table.id} table={table} /> <TableListItem key={table.id} table={table} />

View File

@@ -9,26 +9,29 @@ import { CreateDiagramDialogProvider } from './dialogs/create-diagram-dialog/cre
import { ConfigProvider } from './context/config-context/config-provider'; import { ConfigProvider } from './context/config-context/config-provider';
import { HistoryProvider } from './context/history-context/history-provider'; import { HistoryProvider } from './context/history-context/history-provider';
import { RedoUndoStackProvider } from './context/history-context/redo-undo-stack-provider'; import { RedoUndoStackProvider } from './context/history-context/redo-undo-stack-provider';
import { LayoutProvider } from './context/layout-context/layout-provider';
const routes: RouteObject[] = [ const routes: RouteObject[] = [
...['', 'diagrams/:diagramId'].map((path) => ({ ...['', 'diagrams/:diagramId'].map((path) => ({
path, path,
element: ( element: (
<StorageProvider> <LayoutProvider>
<ConfigProvider> <StorageProvider>
<RedoUndoStackProvider> <ConfigProvider>
<ChartDBProvider> <RedoUndoStackProvider>
<HistoryProvider> <ChartDBProvider>
<CreateDiagramDialogProvider> <HistoryProvider>
<ReactFlowProvider> <CreateDiagramDialogProvider>
<EditorPage /> <ReactFlowProvider>
</ReactFlowProvider> <EditorPage />
</CreateDiagramDialogProvider> </ReactFlowProvider>
</HistoryProvider> </CreateDiagramDialogProvider>
</ChartDBProvider> </HistoryProvider>
</RedoUndoStackProvider> </ChartDBProvider>
</ConfigProvider> </RedoUndoStackProvider>
</StorageProvider> </ConfigProvider>
</StorageProvider>
</LayoutProvider>
), ),
})), })),
{ {