Feat/improve editable cell (#959)
* Removed isSomeInputInEditMode * Removed console.log * Added a first version of generic cell text * Removed metadata from entity table V1 * Fix * Fix * Fix
This commit is contained in:
36
front/src/modules/ui/table/components/EntityTableBodyV2.tsx
Normal file
36
front/src/modules/ui/table/components/EntityTableBodyV2.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { isNavbarSwitchingSizeState } from '@/ui/layout/states/isNavbarSwitchingSizeState';
|
||||
|
||||
import { isFetchingEntityTableDataState } from '../states/isFetchingEntityTableDataState';
|
||||
import { RowIdContext } from '../states/RowIdContext';
|
||||
import { RowIndexContext } from '../states/RowIndexContext';
|
||||
import { tableRowIdsState } from '../states/tableRowIdsState';
|
||||
|
||||
import { EntityTableRow } from './EntityTableRowV2';
|
||||
|
||||
export function EntityTableBody() {
|
||||
const rowIds = useRecoilValue(tableRowIdsState);
|
||||
|
||||
const isNavbarSwitchingSize = useRecoilValue(isNavbarSwitchingSizeState);
|
||||
|
||||
const isFetchingEntityTableData = useRecoilValue(
|
||||
isFetchingEntityTableDataState,
|
||||
);
|
||||
|
||||
if (isFetchingEntityTableData || isNavbarSwitchingSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<tbody>
|
||||
{rowIds.map((rowId, index) => (
|
||||
<RowIdContext.Provider value={rowId} key={rowId}>
|
||||
<RowIndexContext.Provider value={index}>
|
||||
<EntityTableRow rowId={rowId} />
|
||||
</RowIndexContext.Provider>
|
||||
</RowIdContext.Provider>
|
||||
))}
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
50
front/src/modules/ui/table/components/EntityTableCellV2.tsx
Normal file
50
front/src/modules/ui/table/components/EntityTableCellV2.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { useContext } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { GenericEditableCell } from '@/people/table/components/GenericEditableCell';
|
||||
|
||||
import { RecoilScope } from '../../recoil-scope/components/RecoilScope';
|
||||
import { useCurrentRowSelected } from '../hooks/useCurrentRowSelected';
|
||||
import { ColumnIndexContext } from '../states/ColumnIndexContext';
|
||||
import { contextMenuPositionState } from '../states/contextMenuPositionState';
|
||||
import { EntityFieldMetadataContext } from '../states/EntityFieldMetadataContext';
|
||||
|
||||
export function EntityTableCell({ cellIndex }: { cellIndex: number }) {
|
||||
const setContextMenuPosition = useSetRecoilState(contextMenuPositionState);
|
||||
|
||||
const { setCurrentRowSelected } = useCurrentRowSelected();
|
||||
|
||||
function handleContextMenu(event: React.MouseEvent) {
|
||||
event.preventDefault();
|
||||
|
||||
setCurrentRowSelected(true);
|
||||
|
||||
setContextMenuPosition({
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
});
|
||||
}
|
||||
|
||||
const entityFieldMetadata = useContext(EntityFieldMetadataContext);
|
||||
|
||||
if (!entityFieldMetadata) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RecoilScope>
|
||||
<ColumnIndexContext.Provider value={cellIndex}>
|
||||
<td
|
||||
onContextMenu={(event) => handleContextMenu(event)}
|
||||
style={{
|
||||
width: entityFieldMetadata.columnSize,
|
||||
minWidth: entityFieldMetadata.columnSize,
|
||||
maxWidth: entityFieldMetadata.columnSize,
|
||||
}}
|
||||
>
|
||||
<GenericEditableCell entityFieldMetadata={entityFieldMetadata} />
|
||||
</td>
|
||||
</ColumnIndexContext.Provider>
|
||||
</RecoilScope>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { entityFieldMetadataArrayState } from '../states/entityFieldMetadataArrayState';
|
||||
|
||||
import { ColumnHead } from './ColumnHead';
|
||||
import { SelectAllCheckbox } from './SelectAllCheckbox';
|
||||
|
||||
export function EntityTableHeader() {
|
||||
const fieldMetadataArray = useRecoilValue(entityFieldMetadataArrayState);
|
||||
|
||||
return (
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
style={{
|
||||
width: 30,
|
||||
minWidth: 30,
|
||||
maxWidth: 30,
|
||||
}}
|
||||
>
|
||||
<SelectAllCheckbox />
|
||||
</th>
|
||||
{fieldMetadataArray.map((fieldMetadata) => (
|
||||
<th
|
||||
key={fieldMetadata.fieldName.toString()}
|
||||
style={{
|
||||
width: fieldMetadata.columnSize,
|
||||
minWidth: fieldMetadata.columnSize,
|
||||
maxWidth: fieldMetadata.columnSize,
|
||||
}}
|
||||
>
|
||||
<ColumnHead
|
||||
viewName={fieldMetadata.label}
|
||||
viewIcon={fieldMetadata.icon}
|
||||
/>
|
||||
</th>
|
||||
))}
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
}
|
||||
38
front/src/modules/ui/table/components/EntityTableRowV2.tsx
Normal file
38
front/src/modules/ui/table/components/EntityTableRowV2.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { entityFieldMetadataArrayState } from '../states/entityFieldMetadataArrayState';
|
||||
import { EntityFieldMetadataContext } from '../states/EntityFieldMetadataContext';
|
||||
|
||||
import { CheckboxCell } from './CheckboxCell';
|
||||
import { EntityTableCell } from './EntityTableCellV2';
|
||||
|
||||
const StyledRow = styled.tr<{ selected: boolean }>`
|
||||
background: ${(props) =>
|
||||
props.selected ? props.theme.background.secondary : 'none'};
|
||||
`;
|
||||
|
||||
export function EntityTableRow({ rowId }: { rowId: string }) {
|
||||
const entityFieldMetadataArray = useRecoilValue(
|
||||
entityFieldMetadataArrayState,
|
||||
);
|
||||
|
||||
return (
|
||||
<StyledRow data-testid={`row-id-${rowId}`} selected={false}>
|
||||
<td>
|
||||
<CheckboxCell />
|
||||
</td>
|
||||
{entityFieldMetadataArray.map((entityFieldMetadata, columnIndex) => {
|
||||
return (
|
||||
<EntityFieldMetadataContext.Provider
|
||||
value={entityFieldMetadata}
|
||||
key={entityFieldMetadata.fieldName}
|
||||
>
|
||||
<EntityTableCell cellIndex={columnIndex} />
|
||||
</EntityFieldMetadataContext.Provider>
|
||||
);
|
||||
})}
|
||||
<td></td>
|
||||
</StyledRow>
|
||||
);
|
||||
}
|
||||
136
front/src/modules/ui/table/components/EntityTableV2.tsx
Normal file
136
front/src/modules/ui/table/components/EntityTableV2.tsx
Normal file
@ -0,0 +1,136 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
|
||||
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
|
||||
import { useMapKeyboardToSoftFocus } from '../hooks/useMapKeyboardToSoftFocus';
|
||||
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
|
||||
import { TableHeader } from '../table-header/components/TableHeader';
|
||||
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
|
||||
|
||||
import { EntityTableBody } from './EntityTableBodyV2';
|
||||
import { EntityTableHeader } from './EntityTableHeaderV2';
|
||||
|
||||
const StyledTable = styled.table`
|
||||
border-collapse: collapse;
|
||||
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
border-spacing: 0;
|
||||
margin-left: ${({ theme }) => theme.table.horizontalCellMargin};
|
||||
margin-right: ${({ theme }) => theme.table.horizontalCellMargin};
|
||||
table-layout: fixed;
|
||||
width: calc(100% - ${({ theme }) => theme.table.horizontalCellMargin} * 2);
|
||||
|
||||
th {
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-collapse: collapse;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
|
||||
:last-child {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
:first-of-type {
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
:last-of-type {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-collapse: collapse;
|
||||
color: ${({ theme }) => theme.font.color.primary};
|
||||
padding: 0;
|
||||
|
||||
text-align: left;
|
||||
|
||||
:last-child {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
:first-of-type {
|
||||
border-left-color: transparent;
|
||||
border-right-color: transparent;
|
||||
}
|
||||
:last-of-type {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledTableWithHeader = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
const StyledTableWrapper = styled.div`
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
type OwnProps<SortField> = {
|
||||
viewName: string;
|
||||
viewIcon?: React.ReactNode;
|
||||
availableSorts?: Array<SortType<SortField>>;
|
||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
||||
onRowSelectionChange?: (rowSelection: string[]) => void;
|
||||
useUpdateField: EntityUpdateFieldHook;
|
||||
};
|
||||
|
||||
export function EntityTable<SortField>({
|
||||
viewName,
|
||||
viewIcon,
|
||||
availableSorts,
|
||||
onSortsUpdate,
|
||||
useUpdateField,
|
||||
}: OwnProps<SortField>) {
|
||||
const tableBodyRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
useMapKeyboardToSoftFocus();
|
||||
|
||||
const leaveTableFocus = useLeaveTableFocus();
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [tableBodyRef],
|
||||
callback: () => {
|
||||
leaveTableFocus();
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<EntityUpdateFieldHookContext.Provider value={useUpdateField}>
|
||||
<StyledTableWithHeader>
|
||||
<StyledTableContainer ref={tableBodyRef}>
|
||||
<TableHeader
|
||||
viewName={viewName}
|
||||
viewIcon={viewIcon}
|
||||
availableSorts={availableSorts}
|
||||
onSortsUpdate={onSortsUpdate}
|
||||
/>
|
||||
<StyledTableWrapper>
|
||||
<StyledTable>
|
||||
<EntityTableHeader />
|
||||
<EntityTableBody />
|
||||
</StyledTable>
|
||||
</StyledTableWrapper>
|
||||
</StyledTableContainer>
|
||||
</StyledTableWithHeader>
|
||||
</EntityUpdateFieldHookContext.Provider>
|
||||
);
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
|
||||
import { useCloseCurrentCellInEditMode } from '../../hooks/useClearCellInEditMode';
|
||||
import { CellHotkeyScopeContext } from '../../states/CellHotkeyScopeContext';
|
||||
import { isSomeInputInEditModeState } from '../../states/isSomeInputInEditModeState';
|
||||
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
|
||||
|
||||
import { useCurrentCellEditMode } from './useCurrentCellEditMode';
|
||||
@ -29,33 +27,18 @@ export function useEditableCell() {
|
||||
setHotkeyScope(TableHotkeyScope.TableSoftFocus);
|
||||
}
|
||||
|
||||
const openEditableCell = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
() => {
|
||||
const isSomeInputInEditMode = snapshot
|
||||
.getLoadable(isSomeInputInEditModeState)
|
||||
.valueOrThrow();
|
||||
function openEditableCell() {
|
||||
setCurrentCellInEditMode();
|
||||
|
||||
if (!isSomeInputInEditMode) {
|
||||
set(isSomeInputInEditModeState, true);
|
||||
|
||||
setCurrentCellInEditMode();
|
||||
|
||||
if (customCellHotkeyScope) {
|
||||
setHotkeyScope(
|
||||
customCellHotkeyScope.scope,
|
||||
customCellHotkeyScope.customScopes,
|
||||
);
|
||||
} else {
|
||||
setHotkeyScope(
|
||||
DEFAULT_CELL_SCOPE.scope,
|
||||
DEFAULT_CELL_SCOPE.customScopes,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[setCurrentCellInEditMode, setHotkeyScope, customCellHotkeyScope],
|
||||
);
|
||||
if (customCellHotkeyScope) {
|
||||
setHotkeyScope(
|
||||
customCellHotkeyScope.scope,
|
||||
customCellHotkeyScope.customScopes,
|
||||
);
|
||||
} else {
|
||||
setHotkeyScope(DEFAULT_CELL_SCOPE.scope, DEFAULT_CELL_SCOPE.customScopes);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
closeEditableCell,
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { EntityUpdateFieldHookContext } from '../states/EntityUpdateFieldHookContext';
|
||||
|
||||
export function useEntityUpdateFieldHook() {
|
||||
return useContext(EntityUpdateFieldHookContext);
|
||||
}
|
||||
@ -2,7 +2,6 @@ import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { currentCellInEditModePositionState } from '../states/currentCellInEditModePositionState';
|
||||
import { isCellInEditModeFamilyState } from '../states/isCellInEditModeFamilyState';
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
|
||||
export function useCloseCurrentCellInEditMode() {
|
||||
return useRecoilCallback(({ set, snapshot }) => {
|
||||
@ -12,11 +11,6 @@ export function useCloseCurrentCellInEditMode() {
|
||||
);
|
||||
|
||||
set(isCellInEditModeFamilyState(currentCellInEditModePosition), false);
|
||||
|
||||
// TODO: find a way to remove this
|
||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||
|
||||
set(isSomeInputInEditModeState, false);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
@ -4,7 +4,6 @@ import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
import { currentHotkeyScopeState } from '@/ui/hotkey/states/internal/currentHotkeyScopeState';
|
||||
|
||||
import { isSoftFocusActiveState } from '../states/isSoftFocusActiveState';
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
import { TableHotkeyScope } from '../types/TableHotkeyScope';
|
||||
|
||||
import { useCloseCurrentCellInEditMode } from './useClearCellInEditMode';
|
||||
@ -23,19 +22,11 @@ export function useLeaveTableFocus() {
|
||||
.getLoadable(isSoftFocusActiveState)
|
||||
.valueOrThrow();
|
||||
|
||||
const isSomeInputInEditMode = snapshot
|
||||
.getLoadable(isSomeInputInEditModeState)
|
||||
.valueOrThrow();
|
||||
|
||||
const currentHotkeyScope = snapshot
|
||||
.getLoadable(currentHotkeyScopeState)
|
||||
.valueOrThrow();
|
||||
|
||||
if (isSomeInputInEditMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSoftFocusActive && !isSomeInputInEditMode) {
|
||||
if (!isSoftFocusActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
|
||||
import { isSomeInputInEditModeState } from '../states/isSomeInputInEditModeState';
|
||||
import { TableHotkeyScope } from '../types/TableHotkeyScope';
|
||||
|
||||
import { useDisableSoftFocus } from './useDisableSoftFocus';
|
||||
@ -16,50 +14,40 @@ export function useMapKeyboardToSoftFocus() {
|
||||
const disableSoftFocus = useDisableSoftFocus();
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const [isSomeInputInEditMode] = useRecoilState(isSomeInputInEditModeState);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowUp, `${Key.Shift}+${Key.Enter}`],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveUp();
|
||||
}
|
||||
moveUp();
|
||||
},
|
||||
TableHotkeyScope.TableSoftFocus,
|
||||
[moveUp, isSomeInputInEditMode],
|
||||
[moveUp],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
Key.ArrowDown,
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveDown();
|
||||
}
|
||||
moveDown();
|
||||
},
|
||||
TableHotkeyScope.TableSoftFocus,
|
||||
[moveDown, isSomeInputInEditMode],
|
||||
[moveDown],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowLeft, `${Key.Shift}+${Key.Tab}`],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveLeft();
|
||||
}
|
||||
moveLeft();
|
||||
},
|
||||
TableHotkeyScope.TableSoftFocus,
|
||||
[moveLeft, isSomeInputInEditMode],
|
||||
[moveLeft],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.ArrowRight, Key.Tab],
|
||||
() => {
|
||||
if (!isSomeInputInEditMode) {
|
||||
moveRight();
|
||||
}
|
||||
moveRight();
|
||||
},
|
||||
TableHotkeyScope.TableSoftFocus,
|
||||
[moveRight, isSomeInputInEditMode],
|
||||
[moveRight],
|
||||
);
|
||||
|
||||
useScopedHotkeys(
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { EntityFieldMetadata } from '../types/EntityFieldMetadata';
|
||||
|
||||
export const EntityFieldMetadataContext =
|
||||
createContext<EntityFieldMetadata | null>(null);
|
||||
@ -0,0 +1,6 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { EntityUpdateFieldHook } from '../types/CellUpdateFieldHook';
|
||||
|
||||
export const EntityUpdateFieldHookContext =
|
||||
createContext<EntityUpdateFieldHook | null>(null);
|
||||
@ -0,0 +1,8 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { EntityFieldMetadata } from '../types/EntityFieldMetadata';
|
||||
|
||||
export const entityFieldMetadataArrayState = atom<EntityFieldMetadata[]>({
|
||||
key: 'entityFieldMetadataArrayState',
|
||||
default: [],
|
||||
});
|
||||
@ -1,6 +0,0 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isSomeInputInEditModeState = atom<boolean>({
|
||||
key: 'isSomeInputInEditModeState',
|
||||
default: false,
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
export const tableEntitiesFamilyState = atomFamily<
|
||||
Record<string, unknown> | null,
|
||||
string
|
||||
>({
|
||||
key: 'tableEntitiesFamilyState',
|
||||
default: null,
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
import { selectorFamily } from 'recoil';
|
||||
|
||||
import { tableEntitiesFamilyState } from './tableEntitiesFamilyState';
|
||||
|
||||
export const tableEntityFieldFamilySelector = selectorFamily({
|
||||
key: 'tableEntityFieldFamilySelector',
|
||||
get:
|
||||
<T>({ fieldName, entityId }: { fieldName: string; entityId: string }) =>
|
||||
({ get }) =>
|
||||
get(tableEntitiesFamilyState(entityId))?.[fieldName] as T,
|
||||
set:
|
||||
<T>({ fieldName, entityId }: { fieldName: string; entityId: string }) =>
|
||||
({ set }, newValue: T) =>
|
||||
set(tableEntitiesFamilyState(entityId), (prevState) => ({
|
||||
...prevState,
|
||||
[fieldName]: newValue,
|
||||
})),
|
||||
});
|
||||
5
front/src/modules/ui/table/types/CellUpdateFieldHook.ts
Normal file
5
front/src/modules/ui/table/types/CellUpdateFieldHook.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export type EntityUpdateFieldHook = () => <T>(
|
||||
entityId: string,
|
||||
fieldName: string,
|
||||
value: T,
|
||||
) => void | Promise<void>;
|
||||
16
front/src/modules/ui/table/types/EntityFieldMetadata.ts
Normal file
16
front/src/modules/ui/table/types/EntityFieldMetadata.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export type EntityFieldType =
|
||||
| 'text'
|
||||
| 'number'
|
||||
| 'date'
|
||||
| 'select'
|
||||
| 'checkbox'
|
||||
| 'icon';
|
||||
|
||||
export type EntityFieldMetadata = {
|
||||
fieldName: string;
|
||||
label: string;
|
||||
type: EntityFieldType;
|
||||
icon: JSX.Element;
|
||||
columnSize: number;
|
||||
filterIcon?: JSX.Element;
|
||||
};
|
||||
Reference in New Issue
Block a user