Implement table view context

This commit is contained in:
Hakan Shehu
2024-09-04 15:29:54 +02:00
parent 59e5d1e31c
commit 643e4423cf
7 changed files with 132 additions and 43 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Icon } from '@/components/ui/icon';
import { cn } from '@/lib/utils';
import { getDefaultFieldWidth, getFieldIcon } from '@/lib/databases';
import { getFieldIcon } from '@/lib/databases';
import { useDrag, useDrop } from 'react-dnd';
import { Resizable } from 're-resizable';
import { Field } from '@/types/databases';
@@ -13,6 +13,7 @@ import {
import { Separator } from '@/components/ui/separator';
import { FieldDeleteDialog } from '@/components/databases/fields/field-delete-dialog';
import { FieldRenameInput } from '@/components/databases/fields/field-rename-input';
import { useTableView } from '@/contexts/table-view';
interface TableViewFieldHeaderProps {
field: Field;
@@ -23,6 +24,8 @@ export const TableViewFieldHeader = ({
field,
index,
}: TableViewFieldHeaderProps) => {
const tableView = useTableView();
const canEditDatabase = true;
const canEditView = true;
@@ -32,7 +35,7 @@ export const TableViewFieldHeader = ({
type: 'table-field-header',
item: field,
canDrag: () => canEditView,
end: (item, monitor) => {
end: (_item, monitor) => {
const dropResult = monitor.getDropResult<{ index: number }>();
if (!dropResult?.index) return;
@@ -60,18 +63,19 @@ export const TableViewFieldHeader = ({
const divRef = React.useRef<HTMLDivElement>(null);
const dragDropRef = dragRef(dropRef(divRef));
const defaultWidth = getDefaultFieldWidth(field.type);
return (
<React.Fragment>
<Resizable
defaultSize={{
width: defaultWidth,
width: `${tableView.getFieldWidth(field.id, field.type)}px`,
height: '2rem',
}}
minWidth={100}
maxWidth={500}
size={{ width: defaultWidth, height: '2rem' }}
size={{
width: `${tableView.getFieldWidth(field.id, field.type)}px`,
height: '2rem',
}}
enable={{
bottom: false,
bottomLeft: false,
@@ -91,12 +95,9 @@ export const TableViewFieldHeader = ({
right: '-3px',
},
}}
onResizeStop={(e, direction, ref) => {
// const newWidth = ref.offsetWidth;
// view.updateFieldAttrs({
// ...viewField.attrs,
// width: newWidth,
// });
onResizeStop={(_e, _direction, ref) => {
const newWidth = ref.offsetWidth;
tableView.resizeField(field.id, newWidth);
}}
>
<Popover modal={true}>
@@ -160,10 +161,7 @@ export const TableViewFieldHeader = ({
<div
className="flex cursor-pointer flex-row items-center gap-2 p-1 hover:bg-gray-100"
onClick={() => {
// view.updateFieldAttrs({
// ...viewField.attrs,
// visible: false,
// });
tableView.hideField(field.id);
}}
>
<Icon name="eye-off-line" />

View File

@@ -1,20 +1,17 @@
import React from 'react';
import { useDatabase } from '@/contexts/database';
import { useTableView } from '@/contexts/table-view';
import { TableViewNameHeader } from '@/components/databases/tables/table-view-name-header';
import { TableViewFieldHeader } from '@/components/databases/tables/table-view-field-header';
import { FieldCreatePopover } from '@/components/databases/fields/field-create-popover';
export const TableViewHeader = () => {
const database = useDatabase();
const tableView = useTableView();
return (
<div className="flex flex-row items-center gap-0.5">
<div style={{ width: '30px', minWidth: '30px' }} />
<TableViewNameHeader />
{database.fields.map((field, index) => {
// const isVisible =
// viewField.attrs.visible ?? getDefaultFieldVisibility(view.layout);
// if (!isVisible) return null;
{tableView.fields.map((field, index) => {
return (
<TableViewFieldHeader field={field} key={field.id} index={index} />
);

View File

@@ -8,21 +8,22 @@ import {
} from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import { Input } from '@/components/ui/input';
import { useTableView } from '@/contexts/table-view';
export const TableViewNameHeader = () => {
const defaultWidth = '300px';
const tableView = useTableView();
const canEditView = true;
return (
<Resizable
defaultSize={{
width: defaultWidth,
width: `${tableView.getNameWidth()}px`,
height: '2rem',
}}
minWidth={100}
maxWidth={500}
size={{ width: defaultWidth, height: '2rem' }}
size={{ width: `${tableView.getNameWidth()}px`, height: '2rem' }}
enable={{
bottom: false,
bottomLeft: false,
@@ -43,11 +44,8 @@ export const TableViewNameHeader = () => {
},
}}
onResizeStop={(e, direction, ref) => {
// const newWidth = ref.offsetWidth;
// view.updateFieldAttrs({
// ...viewField.attrs,
// width: newWidth,
// });
const newWidth = ref.offsetWidth;
tableView.resizeName(newWidth);
}}
>
<Popover modal={true}>

View File

@@ -1,9 +1,8 @@
import React from 'react';
import { TableViewNameCell } from '@/components/databases/tables/table-view-name-cell';
import { getDefaultFieldWidth } from '@/lib/databases';
import { useDatabase } from '@/contexts/database';
import { TableViewFieldCell } from './table-view-field-cell';
import { RecordNode } from '@/types/databases';
import { useTableView } from '@/contexts/table-view';
interface TableViewRowProps {
index: number;
@@ -11,8 +10,8 @@ interface TableViewRowProps {
}
export const TableViewRow = ({ index, record }: TableViewRowProps) => {
const database = useDatabase();
const nameCellWidth = '300px';
const tableView = useTableView();
return (
<div className="animate-fade-in flex flex-row items-center gap-0.5 border-b">
<span
@@ -23,12 +22,12 @@ export const TableViewRow = ({ index, record }: TableViewRowProps) => {
</span>
<div
className="h-8 border-r"
style={{ width: nameCellWidth, minWidth: nameCellWidth }}
style={{ width: `${tableView.getNameWidth()}px`, minWidth: '300px' }}
>
<TableViewNameCell record={record} />
</div>
{database.fields.map((field) => {
const width = getDefaultFieldWidth(field.type) + 'px';
{tableView.fields.map((field) => {
const width = tableView.getFieldWidth(field.id, field.type);
return (
<div
key={`row-${record.id}-${field.id}`}

View File

@@ -3,17 +3,90 @@ import { LocalNode } from '@/types/nodes';
import { TableViewHeader } from '@/components/databases/tables/table-view-header';
import { TableViewBody } from '@/components/databases/tables/table-view-body';
import { TableViewRecordCreateRow } from '@/components/databases/tables/table-view-record-create-row';
import { TableViewContext } from '@/contexts/table-view';
import { useDatabase } from '@/contexts/database';
import { compareString } from '@/lib/utils';
import { FieldType } from '@/types/databases';
import { getDefaultFieldWidth, getDefaultNameWidth } from '@/lib/databases';
interface TableViewProps {
node: LocalNode;
}
export const TableView = ({ node }: TableViewProps) => {
const database = useDatabase();
const attrs = node.attrs ?? {};
const [hiddenFields, setHiddenFields] = React.useState<string[]>(
attrs.hiddenFields ?? [],
);
const [fieldIndexes, setFieldIndexes] = React.useState<
Record<string, string>
>(attrs.fieldIndexes ?? {});
const [fieldWidths, setFieldWidths] = React.useState<Record<string, number>>(
attrs.fieldWidths ?? {},
);
const [nameWidth, setNameWidth] = React.useState<number>(
attrs.nameWidth ?? getDefaultNameWidth(),
);
React.useEffect(() => {
const attrs = node.attrs ?? {};
setHiddenFields(attrs.hiddenFields ?? []);
setFieldIndexes(attrs.fieldIndexes ?? {});
setFieldWidths(attrs.fieldWidths ?? {});
setNameWidth(attrs.nameWidth ?? getDefaultNameWidth());
}, [node.versionId]);
return (
<div className="mt-2 w-full min-w-full max-w-full overflow-auto pr-5">
<TableViewHeader />
<TableViewBody />
<TableViewRecordCreateRow />
</div>
<TableViewContext.Provider
value={{
id: node.id,
fields: database.fields
.filter((field) => !hiddenFields.includes(field.id))
.sort((a, b) =>
compareString(
fieldIndexes[a.id] ?? a.index,
fieldIndexes[b.id] ?? b.index,
),
),
hideField: (id: string) => {
if (hiddenFields.includes(id)) {
return;
}
setHiddenFields([...hiddenFields, id]);
},
showField: (id: string) => {
if (!hiddenFields.includes(id)) {
return;
}
setHiddenFields(hiddenFields.filter((fieldId) => fieldId !== id));
},
getNameWidth: () => nameWidth,
resizeName: (width: number) => {
setNameWidth(width);
},
getFieldWidth: (id: string, type: FieldType) => {
return fieldWidths[id] ?? getDefaultFieldWidth(type);
},
resizeField: (id, width) => {
setFieldWidths({ ...fieldWidths, [id]: width });
},
moveField: (id, after) => {
setFieldIndexes({
...fieldIndexes,
[id]: fieldIndexes[after],
});
},
}}
>
<div className="mt-2 w-full min-w-full max-w-full overflow-auto pr-5">
<TableViewHeader />
<TableViewBody />
<TableViewRecordCreateRow />
</div>
</TableViewContext.Provider>
);
};

View File

@@ -0,0 +1,20 @@
import { Field, FieldType } from '@/types/databases';
import { createContext, useContext } from 'react';
interface TableViewContext {
id: string;
fields: Field[];
hideField: (id: string) => void;
showField: (id: string) => void;
getNameWidth: () => number;
resizeName: (width: number) => void;
getFieldWidth: (id: string, type: FieldType) => number;
resizeField: (id: string, width: number) => void;
moveField: (id: string, after: string) => void;
}
export const TableViewContext = createContext<TableViewContext>(
{} as TableViewContext,
);
export const useTableView = () => useContext(TableViewContext);

View File

@@ -90,6 +90,10 @@ export const getDefaultFieldWidth = (type: FieldType): number => {
}
};
export const getDefaultNameWidth = (): number => {
return 300;
};
interface SelectOptionColor {
label: string;
value: string;