Refactor ObjectDataTable to work with new views system (#2274)

Complete work
This commit is contained in:
Charles Bochet
2023-10-29 23:50:59 +01:00
committed by GitHub
parent 9bab28912d
commit d38497c46a
39 changed files with 578 additions and 373 deletions

View File

@ -1,6 +1,14 @@
import { useEffect } from 'react';
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableFiltersScopedState } from '@/ui/data/data-table/states/tableFiltersScopedState';
import { tableSortsScopedState } from '@/ui/data/data-table/states/tableSortsScopedState';
import { turnFiltersIntoWhereClauseV2 } from '@/ui/data/filter/utils/turnFiltersIntoWhereClauseV2';
import { turnSortsIntoOrderByV2 } from '@/ui/data/sort/utils/turnSortsIntoOrderByV2';
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
import { useFindManyObjects } from '../hooks/useFindManyObjects';
import { useMetadataObjectInContext } from '../hooks/useMetadataObjectInContext';
import { useSetObjectDataTableData } from '../hooks/useSetDataTableData';
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
@ -9,14 +17,33 @@ export type ObjectDataTableEffectProps = Pick<
'objectNamePlural'
>;
// TODO: merge in a single effect component
// This should be migrated to DataTable at some point
export const ObjectDataTableEffect = ({
objectNamePlural,
}: ObjectDataTableEffectProps) => {
const setDataTableData = useSetObjectDataTableData();
const { foundMetadataObject } = useMetadataObjectInContext();
const tableFilters = useRecoilScopedValue(
tableFiltersScopedState,
TableRecoilScopeContext,
);
const tableSorts = useRecoilScopedValue(
tableSortsScopedState,
TableRecoilScopeContext,
);
const { objects, loading } = useFindManyObjects({
objectNamePlural,
objectNamePlural: objectNamePlural,
filter: turnFiltersIntoWhereClauseV2(
tableFilters,
foundMetadataObject?.fields ?? [],
),
orderBy: turnSortsIntoOrderByV2(
tableSorts,
foundMetadataObject?.fields ?? [],
),
});
useEffect(() => {

View File

@ -9,6 +9,7 @@ import { InlineCell } from '@/ui/data/inline-cell/components/InlineCell';
import { PropertyBox } from '@/ui/data/inline-cell/property-box/components/PropertyBox';
import { InlineCellHotkeyScope } from '@/ui/data/inline-cell/types/InlineCellHotkeyScope';
import { IconBuildingSkyscraper } from '@/ui/display/icon';
import { useLazyLoadIcons } from '@/ui/input/hooks/useLazyLoadIcons';
import { PageBody } from '@/ui/layout/page/PageBody';
import { PageContainer } from '@/ui/layout/page/PageContainer';
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
@ -33,6 +34,8 @@ export const ObjectShowPage = () => {
objectId: string;
}>();
const { icons } = useLazyLoadIcons();
const { foundMetadataObject } = useFindOneMetadataObject({
objectNameSingular,
});
@ -130,6 +133,7 @@ export const ObjectShowPage = () => {
field: metadataField,
position: index,
metadataObject: foundMetadataObject,
icons,
}),
useUpdateEntityMutation: useUpdateOneObjectMutation,
hotkeyScope: InlineCellHotkeyScope.InlineCell,

View File

@ -1,11 +1,23 @@
import styled from '@emotion/styled';
import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { DataTable } from '@/ui/data/data-table/components/DataTable';
import { TableOptionsDropdownId } from '@/ui/data/data-table/constants/TableOptionsDropdownId';
import { TableContext } from '@/ui/data/data-table/contexts/TableContext';
import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown';
import { tableColumnsScopedState } from '@/ui/data/data-table/states/tableColumnsScopedState';
import { tableFiltersScopedState } from '@/ui/data/data-table/states/tableFiltersScopedState';
import { tableSortsScopedState } from '@/ui/data/data-table/states/tableSortsScopedState';
import { ViewBar } from '@/views/components/ViewBar';
import { useViewFields } from '@/views/hooks/internal/useViewFields';
import { useView } from '@/views/hooks/useView';
import { ViewScope } from '@/views/scopes/ViewScope';
import { columnDefinitionsToViewFields } from '@/views/utils/columnDefinitionToViewField';
import { viewFieldsToColumnDefinitions } from '@/views/utils/viewFieldsToColumnDefinitions';
import { viewFiltersToFilters } from '@/views/utils/viewFiltersToFilters';
import { viewSortsToSorts } from '@/views/utils/viewSortsToSorts';
import { useMetadataObjectInContext } from '../hooks/useMetadataObjectInContext';
import { useUpdateOneObject } from '../hooks/useUpdateOneObject';
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
@ -28,9 +40,26 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
const { updateOneObject } = useUpdateOneObject({
objectNamePlural,
});
const { columnDefinitions, foundMetadataObject } =
useMetadataObjectInContext();
const tableScopeId = foundMetadataObject?.namePlural ?? '';
const viewScopeId = objectNamePlural ?? '';
const { persistViewFields } = useViewFields(viewScopeId);
const { setCurrentViewFields } = useView({
viewScopeId,
});
const setTableColumns = useSetRecoilState(
tableColumnsScopedState(tableScopeId),
);
const setTableFilters = useSetRecoilState(
tableFiltersScopedState(tableScopeId),
);
const setTableSorts = useSetRecoilState(tableSortsScopedState(tableScopeId));
const updateEntity = ({
variables,
}: {
@ -48,16 +77,32 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
};
return (
<ViewScope viewScopeId={viewScopeId} onViewFieldsChange={() => {}}>
<ViewScope
viewScopeId={viewScopeId}
onViewFieldsChange={(viewFields) => {
setTableColumns(
viewFieldsToColumnDefinitions(viewFields, columnDefinitions),
);
}}
onViewFiltersChange={(viewFilters) => {
setTableFilters(viewFiltersToFilters(viewFilters));
}}
onViewSortsChange={(viewSorts) => {
setTableSorts(viewSortsToSorts(viewSorts));
}}
>
<StyledContainer>
<TableContext.Provider
value={{
onColumnsChange: () => {},
onColumnsChange: useRecoilCallback(() => (columns) => {
setCurrentViewFields?.(columnDefinitionsToViewFields(columns));
persistViewFields(columnDefinitionsToViewFields(columns));
}),
}}
>
<ViewBar
optionsDropdownButton={<TableOptionsDropdown />}
optionsDropdownScopeId="table-dropdown-option"
optionsDropdownScopeId={TableOptionsDropdownId}
/>
<ObjectTableEffect />
<ObjectDataTableEffect objectNamePlural={objectNamePlural} />

View File

@ -16,69 +16,43 @@ export const ObjectTableEffect = () => {
setViewObjectId,
} = useView();
// const [, setTableColumns] = useRecoilScopedState(
// tableColumnsScopedState,
// TableRecoilScopeContext,
// );
const {
columnDefinitions,
filterDefinitions,
sortDefinitions,
foundMetadataObject,
} = useMetadataObjectInContext();
// const [, setTableSorts] = useRecoilScopedState(
// tableSortsScopedState,
// TableRecoilScopeContext,
// );
// const [, setTableFilters] = useRecoilScopedState(
// tableFiltersScopedState,
// TableRecoilScopeContext,
// );
const { columnDefinitions, objectNamePlural } = useMetadataObjectInContext();
const tableScopeId = foundMetadataObject?.namePlural ?? '';
const setAvailableTableColumns = useSetRecoilState(
availableTableColumnsScopedState(objectNamePlural ?? ''),
availableTableColumnsScopedState(tableScopeId),
);
useEffect(() => {
setAvailableSortDefinitions?.([]); // TODO: extract from metadata fields
setAvailableFilterDefinitions?.([]); // TODO: extract from metadata fields
setAvailableFieldDefinitions?.(columnDefinitions);
setViewObjectId?.(objectNamePlural);
if (!foundMetadataObject) {
return;
}
setViewObjectId?.(foundMetadataObject.id);
setViewType?.(ViewType.Table);
setAvailableSortDefinitions?.(sortDefinitions);
setAvailableFilterDefinitions?.(filterDefinitions);
setAvailableFieldDefinitions?.(columnDefinitions);
setAvailableTableColumns(columnDefinitions);
}, [
setAvailableTableColumns,
setViewObjectId,
setViewType,
columnDefinitions,
objectNamePlural,
setAvailableSortDefinitions,
setAvailableFilterDefinitions,
setAvailableFieldDefinitions,
foundMetadataObject,
sortDefinitions,
filterDefinitions,
]);
// useEffect(() => {
// if (currentViewFields) {
// setTableColumns([...currentViewFields].sort((a, b) => a.index - b.index));
// }
// }, [currentViewFields, setTableColumns]);
// useEffect(() => {
// if (currentViewSorts) {
// setTableSorts(currentViewSorts);
// }
// }, [currentViewFields, currentViewSorts, setTableColumns, setTableSorts]);
// useEffect(() => {
// if (currentViewFilters) {
// setTableFilters(currentViewFilters);
// }
// }, [
// currentViewFields,
// currentViewFilters,
// setTableColumns,
// setTableFilters,
// setTableSorts,
// ]);
return <></>;
};

View File

@ -49,9 +49,7 @@ export const ObjectTablePage = () => {
});
const handleAddButtonClick = async () => {
createOneObject?.({
name: 'Test',
});
createOneObject?.({});
};
return (

View File

@ -2,9 +2,14 @@ import { gql } from '@apollo/client';
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { useLazyLoadIcons } from '@/ui/input/hooks/useLazyLoadIcons';
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
import { formatMetadataFieldAsColumnDefinition } from '../utils/formatMetadataFieldAsColumnDefinition';
import { formatMetadataFieldAsFilterDefinition } from '../utils/formatMetadataFieldAsFilterDefinition';
import { formatMetadataFieldAsSortDefinition } from '../utils/formatMetadataFieldAsSortDefinition';
import { generateCreateOneObjectMutation } from '../utils/generateCreateOneObjectMutation';
import { generateDeleteOneObjectMutation } from '../utils/generateDeleteOneObjectMutation';
import { generateFindManyCustomObjectsQuery } from '../utils/generateFindManyCustomObjectsQuery';
@ -25,6 +30,8 @@ export const useFindOneMetadataObject = ({
object.nameSingular === objectNameSingular,
);
const { icons } = useLazyLoadIcons();
const objectNotFoundInMetadata =
metadataObjects.length === 0 ||
(metadataObjects.length > 0 && !foundMetadataObject);
@ -35,6 +42,23 @@ export const useFindOneMetadataObject = ({
position: index,
field,
metadataObject: foundMetadataObject,
icons,
}),
) ?? [];
const filterDefinitions: FilterDefinition[] =
foundMetadataObject?.fields.map((field) =>
formatMetadataFieldAsFilterDefinition({
field,
icons,
}),
) ?? [];
const sortDefinitions: SortDefinition[] =
foundMetadataObject?.fields.map((field) =>
formatMetadataFieldAsSortDefinition({
field,
icons,
}),
) ?? [];
@ -93,6 +117,8 @@ export const useFindOneMetadataObject = ({
foundMetadataObject,
objectNotFoundInMetadata,
columnDefinitions,
filterDefinitions,
sortDefinitions,
findManyQuery,
findOneQuery,
createOneMutation,

View File

@ -13,15 +13,22 @@ export const useMetadataObjectInContext = () => {
);
}
const { foundMetadataObject, loading, columnDefinitions } =
useFindOneMetadataObject({
objectNamePlural: context.objectNamePlural,
});
const {
foundMetadataObject,
loading,
columnDefinitions,
filterDefinitions,
sortDefinitions,
} = useFindOneMetadataObject({
objectNamePlural: context.objectNamePlural,
});
return {
...context,
foundMetadataObject,
loading,
columnDefinitions,
filterDefinitions,
sortDefinitions,
};
};

View File

@ -3,16 +3,13 @@ import { useRecoilCallback } from 'recoil';
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
import { isFetchingDataTableDataState } from '@/ui/data/data-table/states/isFetchingDataTableDataState';
import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTableRowsState';
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
import { useView } from '@/views/hooks/useView';
export const useSetObjectDataTableData = () => {
const resetTableRowSelection = useResetTableRowSelection();
const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext);
const { setEntityCountInCurrentView } = useView();
return useRecoilCallback(
({ set, snapshot }) =>
@ -40,14 +37,10 @@ export const useSetObjectDataTableData = () => {
resetTableRowSelection();
set(numberOfTableRowsState, entityIds.length);
set(
availableSortDefinitionsScopedState({ scopeId: tableContextScopeId }),
[],
);
setEntityCountInCurrentView(entityIds.length);
set(isFetchingDataTableDataState, false);
},
[resetTableRowSelection, tableContextScopeId],
[resetTableRowSelection, setEntityCountInCurrentView],
);
};

View File

@ -1,30 +1,20 @@
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
import { FieldType } from '@/ui/data/field/types/FieldType';
import { IconBrandLinkedin } from '@/ui/display/icon';
import { MetadataObject } from '../types/MetadataObject';
const parseFieldType = (fieldType: string): FieldType => {
if (fieldType === 'url') {
return 'urlV2';
}
if (fieldType === 'money') {
return 'moneyAmountV2';
}
return fieldType as FieldType;
};
import { parseFieldType } from './parseFieldType';
export const formatMetadataFieldAsColumnDefinition = ({
position,
field,
metadataObject,
icons,
}: {
position: number;
field: MetadataObject['fields'][0];
metadataObject: Omit<MetadataObject, 'fields'>;
icons: Record<string, any>;
}): ColumnDefinition<FieldMetadata> => ({
position,
fieldId: field.id,
@ -35,7 +25,7 @@ export const formatMetadataFieldAsColumnDefinition = ({
fieldName: field.name,
placeHolder: field.label,
},
Icon: IconBrandLinkedin,
Icon: icons[field.icon ?? 'Icon123'],
isVisible: true,
basePathToShowPage: `/object/${metadataObject.nameSingular}/`,
});

View File

@ -0,0 +1,16 @@
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
import { MetadataObject } from '../types/MetadataObject';
export const formatMetadataFieldAsFilterDefinition = ({
field,
icons,
}: {
field: MetadataObject['fields'][0];
icons: Record<string, any>;
}): FilterDefinition => ({
fieldId: field.id,
label: field.label,
Icon: icons[field.icon ?? 'Icon123'],
type: 'text',
});

View File

@ -0,0 +1,15 @@
import { SortDefinition } from '@/ui/data/sort/types/SortDefinition';
import { MetadataObject } from '../types/MetadataObject';
export const formatMetadataFieldAsSortDefinition = ({
field,
icons,
}: {
field: MetadataObject['fields'][0];
icons: Record<string, any>;
}): SortDefinition => ({
fieldId: field.id,
label: field.label,
Icon: icons[field.icon ?? 'Icon123'],
});

View File

@ -0,0 +1,13 @@
import { FieldType } from '@/ui/data/field/types/FieldType';
export const parseFieldType = (fieldType: string): FieldType => {
if (fieldType === 'url') {
return 'urlV2';
}
if (fieldType === 'money') {
return 'moneyAmountV2';
}
return fieldType as FieldType;
};