Refactor ObjectDataTable to work with new views system (#2274)
Complete work
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { selectedRowIdsSelector } from '@/ui/data/data-table/states/selectors/selectedRowIdsSelector';
|
import { selectedRowIdsSelector } from '@/ui/data/data-table/states/selectors/selectedRowIdsSelector';
|
||||||
import { ActivityType } from '~/generated/graphql';
|
import { ActivityType } from '~/generated/graphql';
|
||||||
@ -11,27 +11,31 @@ import {
|
|||||||
import { useOpenCreateActivityDrawer } from './useOpenCreateActivityDrawer';
|
import { useOpenCreateActivityDrawer } from './useOpenCreateActivityDrawer';
|
||||||
|
|
||||||
export const useOpenCreateActivityDrawerForSelectedRowIds = () => {
|
export const useOpenCreateActivityDrawerForSelectedRowIds = () => {
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
|
||||||
|
|
||||||
const openCreateActivityDrawer = useOpenCreateActivityDrawer();
|
const openCreateActivityDrawer = useOpenCreateActivityDrawer();
|
||||||
|
|
||||||
return (
|
return useRecoilCallback(
|
||||||
type: ActivityType,
|
({ snapshot }) =>
|
||||||
entityType: ActivityTargetableEntityType,
|
(
|
||||||
relatedEntities?: ActivityTargetableEntity[],
|
type: ActivityType,
|
||||||
) => {
|
entityType: ActivityTargetableEntityType,
|
||||||
let activityTargetableEntityArray: ActivityTargetableEntity[] =
|
relatedEntities?: ActivityTargetableEntity[],
|
||||||
selectedRowIds.map((id) => ({
|
) => {
|
||||||
type: entityType,
|
const selectedRowIds = Object.keys(
|
||||||
id,
|
snapshot.getLoadable(selectedRowIdsSelector).getValue(),
|
||||||
}));
|
);
|
||||||
if (relatedEntities) {
|
let activityTargetableEntityArray: ActivityTargetableEntity[] =
|
||||||
activityTargetableEntityArray =
|
selectedRowIds.map((id) => ({
|
||||||
activityTargetableEntityArray.concat(relatedEntities);
|
type: entityType,
|
||||||
}
|
id,
|
||||||
openCreateActivityDrawer({
|
}));
|
||||||
type,
|
if (relatedEntities) {
|
||||||
targetableEntities: activityTargetableEntityArray,
|
activityTargetableEntityArray =
|
||||||
});
|
activityTargetableEntityArray.concat(relatedEntities);
|
||||||
};
|
}
|
||||||
|
openCreateActivityDrawer({
|
||||||
|
type,
|
||||||
|
targetableEntities: activityTargetableEntityArray,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
import { useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
|
||||||
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
|
||||||
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/display/icon';
|
|
||||||
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
|
||||||
import { ActivityType } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
|
||||||
|
|
||||||
export const useCompanyTableActionBarEntries = () => {
|
|
||||||
const setActionBarEntries = useSetRecoilState(actionBarEntriesState);
|
|
||||||
|
|
||||||
const openCreateActivityRightDrawer =
|
|
||||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
|
||||||
|
|
||||||
const handleActivityClick = async (type: ActivityType) => {
|
|
||||||
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
|
||||||
return {
|
|
||||||
setActionBarEntries: () =>
|
|
||||||
setActionBarEntries([
|
|
||||||
{
|
|
||||||
label: 'Note',
|
|
||||||
Icon: IconNotes,
|
|
||||||
onClick: () => handleActivityClick(ActivityType.Note),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Task',
|
|
||||||
Icon: IconCheckbox,
|
|
||||||
onClick: () => handleActivityClick(ActivityType.Task),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Delete',
|
|
||||||
Icon: IconTrash,
|
|
||||||
accent: 'danger',
|
|
||||||
onClick: () => deleteSelectedCompanies(),
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,10 +1,10 @@
|
|||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
|
||||||
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
|
||||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
||||||
import { selectedRowIdsSelector } from '@/ui/data/data-table/states/selectors/selectedRowIdsSelector';
|
import { selectedRowIdsSelector } from '@/ui/data/data-table/states/selectors/selectedRowIdsSelector';
|
||||||
|
import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
|
||||||
import {
|
import {
|
||||||
IconCheckbox,
|
IconCheckbox,
|
||||||
IconHeart,
|
IconHeart,
|
||||||
@ -12,58 +12,103 @@ import {
|
|||||||
IconNotes,
|
IconNotes,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
} from '@/ui/display/icon';
|
} from '@/ui/display/icon';
|
||||||
|
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
||||||
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
|
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
|
||||||
import { ActivityType, useGetFavoritesQuery } from '~/generated/graphql';
|
import {
|
||||||
|
ActivityType,
|
||||||
|
useDeleteManyCompaniesMutation,
|
||||||
|
useGetFavoritesQuery,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
import { useDeleteSelectedComapnies } from './useDeleteCompanies';
|
import { GET_COMPANY } from '../graphql/queries/getCompany';
|
||||||
|
|
||||||
|
import { useCreateActivityForCompany } from './useCreateActivityForCompany';
|
||||||
|
|
||||||
export const useCompanyTableContextMenuEntries = () => {
|
export const useCompanyTableContextMenuEntries = () => {
|
||||||
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
||||||
|
const setActionBarEntriesState = useSetRecoilState(actionBarEntriesState);
|
||||||
|
const createActivityForCompany = useCreateActivityForCompany();
|
||||||
|
|
||||||
const openCreateActivityRightDrawer =
|
const setTableRowIds = useSetRecoilState(tableRowIdsState);
|
||||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
|
||||||
|
|
||||||
const handleButtonClick = async (type: ActivityType) => {
|
|
||||||
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
|
||||||
};
|
|
||||||
|
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
|
||||||
|
|
||||||
const selectedCompanyId =
|
|
||||||
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
|
||||||
|
|
||||||
const { insertCompanyFavorite, deleteCompanyFavorite } = useFavorites();
|
|
||||||
|
|
||||||
const resetRowSelection = useResetTableRowSelection();
|
const resetRowSelection = useResetTableRowSelection();
|
||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
|
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
|
const { insertCompanyFavorite, deleteCompanyFavorite } = useFavorites();
|
||||||
|
|
||||||
const isFavorite =
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
!!selectedCompanyId &&
|
const selectedRowIds = snapshot
|
||||||
!!favorites?.find((favorite) => favorite.company?.id === selectedCompanyId);
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedCompanyId =
|
||||||
|
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedCompanyId &&
|
||||||
|
!!favorites?.find(
|
||||||
|
(favorite) => favorite.company?.id === selectedCompanyId,
|
||||||
|
);
|
||||||
|
|
||||||
const handleFavoriteButtonClick = () => {
|
|
||||||
resetRowSelection();
|
resetRowSelection();
|
||||||
if (isFavorite) deleteCompanyFavorite(selectedCompanyId);
|
if (isFavorite) deleteCompanyFavorite(selectedCompanyId);
|
||||||
else insertCompanyFavorite(selectedCompanyId);
|
else insertCompanyFavorite(selectedCompanyId);
|
||||||
};
|
});
|
||||||
|
|
||||||
const deleteSelectedCompanies = useDeleteSelectedComapnies();
|
const [deleteManyCompany] = useDeleteManyCompaniesMutation({
|
||||||
|
refetchQueries: [getOperationName(GET_COMPANY) ?? ''],
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDeleteClick = useRecoilCallback(({ snapshot }) => async () => {
|
||||||
|
const rowIdsToDelete = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
resetRowSelection();
|
||||||
|
|
||||||
|
await deleteManyCompany({
|
||||||
|
variables: {
|
||||||
|
ids: rowIdsToDelete,
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
__typename: 'Mutation',
|
||||||
|
deleteManyCompany: {
|
||||||
|
count: rowIdsToDelete.length,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: () => {
|
||||||
|
setTableRowIds((tableRowIds) =>
|
||||||
|
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setContextMenuEntries: () =>
|
setContextMenuEntries: useRecoilCallback(({ snapshot }) => () => {
|
||||||
|
const selectedRowIds = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedCompanyId =
|
||||||
|
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedCompanyId &&
|
||||||
|
!!favorites?.find(
|
||||||
|
(favorite) => favorite.company?.id === selectedCompanyId,
|
||||||
|
);
|
||||||
|
|
||||||
setContextMenuEntries([
|
setContextMenuEntries([
|
||||||
{
|
{
|
||||||
label: 'New task',
|
label: 'New task',
|
||||||
Icon: IconCheckbox,
|
Icon: IconCheckbox,
|
||||||
onClick: () => handleButtonClick(ActivityType.Task),
|
onClick: () => createActivityForCompany(ActivityType.Task),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'New note',
|
label: 'New note',
|
||||||
Icon: IconNotes,
|
Icon: IconNotes,
|
||||||
onClick: () => handleButtonClick(ActivityType.Note),
|
onClick: () => createActivityForCompany(ActivityType.Note),
|
||||||
},
|
},
|
||||||
...(!!selectedCompanyId
|
...(!!selectedCompanyId
|
||||||
? [
|
? [
|
||||||
@ -80,8 +125,29 @@ export const useCompanyTableContextMenuEntries = () => {
|
|||||||
label: 'Delete',
|
label: 'Delete',
|
||||||
Icon: IconTrash,
|
Icon: IconTrash,
|
||||||
accent: 'danger',
|
accent: 'danger',
|
||||||
onClick: () => deleteSelectedCompanies(),
|
onClick: () => handleDeleteClick(),
|
||||||
},
|
},
|
||||||
]),
|
]);
|
||||||
|
}),
|
||||||
|
setActionBarEntries: useRecoilCallback(() => () => {
|
||||||
|
setActionBarEntriesState([
|
||||||
|
{
|
||||||
|
label: 'Task',
|
||||||
|
Icon: IconCheckbox,
|
||||||
|
onClick: () => createActivityForCompany(ActivityType.Task),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Note',
|
||||||
|
Icon: IconNotes,
|
||||||
|
onClick: () => createActivityForCompany(ActivityType.Note),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Delete',
|
||||||
|
Icon: IconTrash,
|
||||||
|
accent: 'danger',
|
||||||
|
onClick: () => handleDeleteClick(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
||||||
|
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
||||||
|
import { ActivityType } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const useCreateActivityForCompany = () => {
|
||||||
|
const openCreateActivityRightDrawer =
|
||||||
|
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||||
|
|
||||||
|
return useRecoilCallback(
|
||||||
|
() => (type: ActivityType) => {
|
||||||
|
openCreateActivityRightDrawer(type, ActivityTargetableEntityType.Company);
|
||||||
|
},
|
||||||
|
[openCreateActivityRightDrawer],
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -3,7 +3,6 @@ import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions';
|
import { companiesAvailableFieldDefinitions } from '@/companies/constants/companiesAvailableFieldDefinitions';
|
||||||
import { getCompaniesOptimisticEffectDefinition } from '@/companies/graphql/optimistic-effect-definitions/getCompaniesOptimisticEffectDefinition';
|
import { getCompaniesOptimisticEffectDefinition } from '@/companies/graphql/optimistic-effect-definitions/getCompaniesOptimisticEffectDefinition';
|
||||||
import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries';
|
|
||||||
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
||||||
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
||||||
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
||||||
@ -63,8 +62,8 @@ export const CompanyTable = () => {
|
|||||||
viewScopeId,
|
viewScopeId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setContextMenuEntries } = useCompanyTableContextMenuEntries();
|
const { setContextMenuEntries, setActionBarEntries } =
|
||||||
const { setActionBarEntries } = useCompanyTableActionBarEntries();
|
useCompanyTableContextMenuEntries();
|
||||||
|
|
||||||
const updateCompany = async (
|
const updateCompany = async (
|
||||||
variables: UpdateOneCompanyMutationVariables,
|
variables: UpdateOneCompanyMutationVariables,
|
||||||
|
|||||||
@ -40,24 +40,6 @@ const CompanyTableEffect = () => {
|
|||||||
setViewType,
|
setViewType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (currentViewSorts) {
|
|
||||||
// setTableSorts(currentViewSorts);
|
|
||||||
// }
|
|
||||||
// }, [currentViewFields, currentViewSorts, setTableColumns, setTableSorts]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (currentViewFilters) {
|
|
||||||
// setTableFilters(currentViewFilters);
|
|
||||||
// }
|
|
||||||
// }, [
|
|
||||||
// currentViewFields,
|
|
||||||
// currentViewFilters,
|
|
||||||
// setTableColumns,
|
|
||||||
// setTableFilters,
|
|
||||||
// setTableSorts,
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export const CompanyTableMockDataEffect = () => {
|
|||||||
const setDataTableData = useSetDataTableData();
|
const setDataTableData = useSetDataTableData();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDataTableData(mockedCompaniesData, [], []);
|
setDataTableData(mockedCompaniesData);
|
||||||
setTableColumns(companiesAvailableFieldDefinitions);
|
setTableColumns(companiesAvailableFieldDefinitions);
|
||||||
}, [setDataTableData, setTableColumns]);
|
}, [setDataTableData, setTableColumns]);
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,35 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
||||||
|
import { TableOptionsDropdownId } from '@/ui/data/data-table/constants/TableOptionsDropdownId';
|
||||||
|
import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown';
|
||||||
|
import { ViewBar } from '@/views/components/ViewBar';
|
||||||
import { ViewScope } from '@/views/scopes/ViewScope';
|
import { ViewScope } from '@/views/scopes/ViewScope';
|
||||||
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
|
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import CompanyTableEffect from './CompanyTableEffect';
|
||||||
import { CompanyTableMockDataEffect } from './CompanyTableMockDataEffect';
|
import { CompanyTableMockDataEffect } from './CompanyTableMockDataEffect';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
export const CompanyTableMockMode = () => {
|
export const CompanyTableMockMode = () => {
|
||||||
return (
|
return (
|
||||||
<ViewScope viewScopeId="company-table-mock-mode">
|
<StyledContainer>
|
||||||
<CompanyTableMockDataEffect />
|
<ViewScope viewScopeId="company-table-mock-mode">
|
||||||
|
<CompanyTableEffect />
|
||||||
|
<CompanyTableMockDataEffect />
|
||||||
|
<ViewBar
|
||||||
|
optionsDropdownButton={<TableOptionsDropdown />}
|
||||||
|
optionsDropdownScopeId={TableOptionsDropdownId}
|
||||||
|
/>
|
||||||
|
|
||||||
<DataTable updateEntityMutation={useUpdateOneCompanyMutation} />
|
<DataTable updateEntityMutation={useUpdateOneCompanyMutation} />
|
||||||
</ViewScope>
|
</ViewScope>
|
||||||
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
import { useEffect } from 'react';
|
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 { useFindManyObjects } from '../hooks/useFindManyObjects';
|
||||||
|
import { useMetadataObjectInContext } from '../hooks/useMetadataObjectInContext';
|
||||||
import { useSetObjectDataTableData } from '../hooks/useSetDataTableData';
|
import { useSetObjectDataTableData } from '../hooks/useSetDataTableData';
|
||||||
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
||||||
|
|
||||||
@ -9,14 +17,33 @@ export type ObjectDataTableEffectProps = Pick<
|
|||||||
'objectNamePlural'
|
'objectNamePlural'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
// TODO: merge in a single effect component
|
// This should be migrated to DataTable at some point
|
||||||
export const ObjectDataTableEffect = ({
|
export const ObjectDataTableEffect = ({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
}: ObjectDataTableEffectProps) => {
|
}: ObjectDataTableEffectProps) => {
|
||||||
const setDataTableData = useSetObjectDataTableData();
|
const setDataTableData = useSetObjectDataTableData();
|
||||||
|
const { foundMetadataObject } = useMetadataObjectInContext();
|
||||||
|
|
||||||
|
const tableFilters = useRecoilScopedValue(
|
||||||
|
tableFiltersScopedState,
|
||||||
|
TableRecoilScopeContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tableSorts = useRecoilScopedValue(
|
||||||
|
tableSortsScopedState,
|
||||||
|
TableRecoilScopeContext,
|
||||||
|
);
|
||||||
|
|
||||||
const { objects, loading } = useFindManyObjects({
|
const { objects, loading } = useFindManyObjects({
|
||||||
objectNamePlural,
|
objectNamePlural: objectNamePlural,
|
||||||
|
filter: turnFiltersIntoWhereClauseV2(
|
||||||
|
tableFilters,
|
||||||
|
foundMetadataObject?.fields ?? [],
|
||||||
|
),
|
||||||
|
orderBy: turnSortsIntoOrderByV2(
|
||||||
|
tableSorts,
|
||||||
|
foundMetadataObject?.fields ?? [],
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -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 { PropertyBox } from '@/ui/data/inline-cell/property-box/components/PropertyBox';
|
||||||
import { InlineCellHotkeyScope } from '@/ui/data/inline-cell/types/InlineCellHotkeyScope';
|
import { InlineCellHotkeyScope } from '@/ui/data/inline-cell/types/InlineCellHotkeyScope';
|
||||||
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
||||||
|
import { useLazyLoadIcons } from '@/ui/input/hooks/useLazyLoadIcons';
|
||||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||||
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
|
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
|
||||||
@ -33,6 +34,8 @@ export const ObjectShowPage = () => {
|
|||||||
objectId: string;
|
objectId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
const { icons } = useLazyLoadIcons();
|
||||||
|
|
||||||
const { foundMetadataObject } = useFindOneMetadataObject({
|
const { foundMetadataObject } = useFindOneMetadataObject({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
@ -130,6 +133,7 @@ export const ObjectShowPage = () => {
|
|||||||
field: metadataField,
|
field: metadataField,
|
||||||
position: index,
|
position: index,
|
||||||
metadataObject: foundMetadataObject,
|
metadataObject: foundMetadataObject,
|
||||||
|
icons,
|
||||||
}),
|
}),
|
||||||
useUpdateEntityMutation: useUpdateOneObjectMutation,
|
useUpdateEntityMutation: useUpdateOneObjectMutation,
|
||||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||||
|
|||||||
@ -1,11 +1,23 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
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 { TableContext } from '@/ui/data/data-table/contexts/TableContext';
|
||||||
import { TableOptionsDropdown } from '@/ui/data/data-table/options/components/TableOptionsDropdown';
|
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 { 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 { 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 { useUpdateOneObject } from '../hooks/useUpdateOneObject';
|
||||||
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
||||||
|
|
||||||
@ -28,9 +40,26 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
|
|||||||
const { updateOneObject } = useUpdateOneObject({
|
const { updateOneObject } = useUpdateOneObject({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
});
|
});
|
||||||
|
const { columnDefinitions, foundMetadataObject } =
|
||||||
|
useMetadataObjectInContext();
|
||||||
|
const tableScopeId = foundMetadataObject?.namePlural ?? '';
|
||||||
const viewScopeId = objectNamePlural ?? '';
|
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 = ({
|
const updateEntity = ({
|
||||||
variables,
|
variables,
|
||||||
}: {
|
}: {
|
||||||
@ -48,16 +77,32 @@ export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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>
|
<StyledContainer>
|
||||||
<TableContext.Provider
|
<TableContext.Provider
|
||||||
value={{
|
value={{
|
||||||
onColumnsChange: () => {},
|
onColumnsChange: useRecoilCallback(() => (columns) => {
|
||||||
|
setCurrentViewFields?.(columnDefinitionsToViewFields(columns));
|
||||||
|
persistViewFields(columnDefinitionsToViewFields(columns));
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ViewBar
|
<ViewBar
|
||||||
optionsDropdownButton={<TableOptionsDropdown />}
|
optionsDropdownButton={<TableOptionsDropdown />}
|
||||||
optionsDropdownScopeId="table-dropdown-option"
|
optionsDropdownScopeId={TableOptionsDropdownId}
|
||||||
/>
|
/>
|
||||||
<ObjectTableEffect />
|
<ObjectTableEffect />
|
||||||
<ObjectDataTableEffect objectNamePlural={objectNamePlural} />
|
<ObjectDataTableEffect objectNamePlural={objectNamePlural} />
|
||||||
|
|||||||
@ -16,69 +16,43 @@ export const ObjectTableEffect = () => {
|
|||||||
setViewObjectId,
|
setViewObjectId,
|
||||||
} = useView();
|
} = useView();
|
||||||
|
|
||||||
// const [, setTableColumns] = useRecoilScopedState(
|
const {
|
||||||
// tableColumnsScopedState,
|
columnDefinitions,
|
||||||
// TableRecoilScopeContext,
|
filterDefinitions,
|
||||||
// );
|
sortDefinitions,
|
||||||
|
foundMetadataObject,
|
||||||
|
} = useMetadataObjectInContext();
|
||||||
|
|
||||||
// const [, setTableSorts] = useRecoilScopedState(
|
const tableScopeId = foundMetadataObject?.namePlural ?? '';
|
||||||
// tableSortsScopedState,
|
|
||||||
// TableRecoilScopeContext,
|
|
||||||
// );
|
|
||||||
|
|
||||||
// const [, setTableFilters] = useRecoilScopedState(
|
|
||||||
// tableFiltersScopedState,
|
|
||||||
// TableRecoilScopeContext,
|
|
||||||
// );
|
|
||||||
|
|
||||||
const { columnDefinitions, objectNamePlural } = useMetadataObjectInContext();
|
|
||||||
|
|
||||||
const setAvailableTableColumns = useSetRecoilState(
|
const setAvailableTableColumns = useSetRecoilState(
|
||||||
availableTableColumnsScopedState(objectNamePlural ?? ''),
|
availableTableColumnsScopedState(tableScopeId),
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAvailableSortDefinitions?.([]); // TODO: extract from metadata fields
|
if (!foundMetadataObject) {
|
||||||
setAvailableFilterDefinitions?.([]); // TODO: extract from metadata fields
|
return;
|
||||||
setAvailableFieldDefinitions?.(columnDefinitions);
|
}
|
||||||
setViewObjectId?.(objectNamePlural);
|
setViewObjectId?.(foundMetadataObject.id);
|
||||||
setViewType?.(ViewType.Table);
|
setViewType?.(ViewType.Table);
|
||||||
|
|
||||||
|
setAvailableSortDefinitions?.(sortDefinitions);
|
||||||
|
setAvailableFilterDefinitions?.(filterDefinitions);
|
||||||
|
setAvailableFieldDefinitions?.(columnDefinitions);
|
||||||
|
|
||||||
setAvailableTableColumns(columnDefinitions);
|
setAvailableTableColumns(columnDefinitions);
|
||||||
}, [
|
}, [
|
||||||
setAvailableTableColumns,
|
setAvailableTableColumns,
|
||||||
setViewObjectId,
|
setViewObjectId,
|
||||||
setViewType,
|
setViewType,
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
objectNamePlural,
|
|
||||||
setAvailableSortDefinitions,
|
setAvailableSortDefinitions,
|
||||||
setAvailableFilterDefinitions,
|
setAvailableFilterDefinitions,
|
||||||
setAvailableFieldDefinitions,
|
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 <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -49,9 +49,7 @@ export const ObjectTablePage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleAddButtonClick = async () => {
|
const handleAddButtonClick = async () => {
|
||||||
createOneObject?.({
|
createOneObject?.({});
|
||||||
name: 'Test',
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,9 +2,14 @@ import { gql } from '@apollo/client';
|
|||||||
|
|
||||||
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
|
||||||
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
|
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 { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
||||||
import { formatMetadataFieldAsColumnDefinition } from '../utils/formatMetadataFieldAsColumnDefinition';
|
import { formatMetadataFieldAsColumnDefinition } from '../utils/formatMetadataFieldAsColumnDefinition';
|
||||||
|
import { formatMetadataFieldAsFilterDefinition } from '../utils/formatMetadataFieldAsFilterDefinition';
|
||||||
|
import { formatMetadataFieldAsSortDefinition } from '../utils/formatMetadataFieldAsSortDefinition';
|
||||||
import { generateCreateOneObjectMutation } from '../utils/generateCreateOneObjectMutation';
|
import { generateCreateOneObjectMutation } from '../utils/generateCreateOneObjectMutation';
|
||||||
import { generateDeleteOneObjectMutation } from '../utils/generateDeleteOneObjectMutation';
|
import { generateDeleteOneObjectMutation } from '../utils/generateDeleteOneObjectMutation';
|
||||||
import { generateFindManyCustomObjectsQuery } from '../utils/generateFindManyCustomObjectsQuery';
|
import { generateFindManyCustomObjectsQuery } from '../utils/generateFindManyCustomObjectsQuery';
|
||||||
@ -25,6 +30,8 @@ export const useFindOneMetadataObject = ({
|
|||||||
object.nameSingular === objectNameSingular,
|
object.nameSingular === objectNameSingular,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { icons } = useLazyLoadIcons();
|
||||||
|
|
||||||
const objectNotFoundInMetadata =
|
const objectNotFoundInMetadata =
|
||||||
metadataObjects.length === 0 ||
|
metadataObjects.length === 0 ||
|
||||||
(metadataObjects.length > 0 && !foundMetadataObject);
|
(metadataObjects.length > 0 && !foundMetadataObject);
|
||||||
@ -35,6 +42,23 @@ export const useFindOneMetadataObject = ({
|
|||||||
position: index,
|
position: index,
|
||||||
field,
|
field,
|
||||||
metadataObject: foundMetadataObject,
|
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,
|
foundMetadataObject,
|
||||||
objectNotFoundInMetadata,
|
objectNotFoundInMetadata,
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
|
filterDefinitions,
|
||||||
|
sortDefinitions,
|
||||||
findManyQuery,
|
findManyQuery,
|
||||||
findOneQuery,
|
findOneQuery,
|
||||||
createOneMutation,
|
createOneMutation,
|
||||||
|
|||||||
@ -13,15 +13,22 @@ export const useMetadataObjectInContext = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { foundMetadataObject, loading, columnDefinitions } =
|
const {
|
||||||
useFindOneMetadataObject({
|
foundMetadataObject,
|
||||||
objectNamePlural: context.objectNamePlural,
|
loading,
|
||||||
});
|
columnDefinitions,
|
||||||
|
filterDefinitions,
|
||||||
|
sortDefinitions,
|
||||||
|
} = useFindOneMetadataObject({
|
||||||
|
objectNamePlural: context.objectNamePlural,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...context,
|
...context,
|
||||||
foundMetadataObject,
|
foundMetadataObject,
|
||||||
loading,
|
loading,
|
||||||
columnDefinitions,
|
columnDefinitions,
|
||||||
|
filterDefinitions,
|
||||||
|
sortDefinitions,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,16 +3,13 @@ import { useRecoilCallback } from 'recoil';
|
|||||||
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
||||||
import { isFetchingDataTableDataState } from '@/ui/data/data-table/states/isFetchingDataTableDataState';
|
import { isFetchingDataTableDataState } from '@/ui/data/data-table/states/isFetchingDataTableDataState';
|
||||||
import { numberOfTableRowsState } from '@/ui/data/data-table/states/numberOfTableRowsState';
|
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 { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
|
||||||
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
|
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
|
||||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
import { useView } from '@/views/hooks/useView';
|
||||||
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
|
|
||||||
|
|
||||||
export const useSetObjectDataTableData = () => {
|
export const useSetObjectDataTableData = () => {
|
||||||
const resetTableRowSelection = useResetTableRowSelection();
|
const resetTableRowSelection = useResetTableRowSelection();
|
||||||
|
const { setEntityCountInCurrentView } = useView();
|
||||||
const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext);
|
|
||||||
|
|
||||||
return useRecoilCallback(
|
return useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
@ -40,14 +37,10 @@ export const useSetObjectDataTableData = () => {
|
|||||||
resetTableRowSelection();
|
resetTableRowSelection();
|
||||||
|
|
||||||
set(numberOfTableRowsState, entityIds.length);
|
set(numberOfTableRowsState, entityIds.length);
|
||||||
|
setEntityCountInCurrentView(entityIds.length);
|
||||||
set(
|
|
||||||
availableSortDefinitionsScopedState({ scopeId: tableContextScopeId }),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
set(isFetchingDataTableDataState, false);
|
set(isFetchingDataTableDataState, false);
|
||||||
},
|
},
|
||||||
[resetTableRowSelection, tableContextScopeId],
|
[resetTableRowSelection, setEntityCountInCurrentView],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,30 +1,20 @@
|
|||||||
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
|
import { ColumnDefinition } from '@/ui/data/data-table/types/ColumnDefinition';
|
||||||
import { FieldMetadata } from '@/ui/data/field/types/FieldMetadata';
|
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';
|
import { MetadataObject } from '../types/MetadataObject';
|
||||||
|
|
||||||
const parseFieldType = (fieldType: string): FieldType => {
|
import { parseFieldType } from './parseFieldType';
|
||||||
if (fieldType === 'url') {
|
|
||||||
return 'urlV2';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldType === 'money') {
|
|
||||||
return 'moneyAmountV2';
|
|
||||||
}
|
|
||||||
|
|
||||||
return fieldType as FieldType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const formatMetadataFieldAsColumnDefinition = ({
|
export const formatMetadataFieldAsColumnDefinition = ({
|
||||||
position,
|
position,
|
||||||
field,
|
field,
|
||||||
metadataObject,
|
metadataObject,
|
||||||
|
icons,
|
||||||
}: {
|
}: {
|
||||||
position: number;
|
position: number;
|
||||||
field: MetadataObject['fields'][0];
|
field: MetadataObject['fields'][0];
|
||||||
metadataObject: Omit<MetadataObject, 'fields'>;
|
metadataObject: Omit<MetadataObject, 'fields'>;
|
||||||
|
icons: Record<string, any>;
|
||||||
}): ColumnDefinition<FieldMetadata> => ({
|
}): ColumnDefinition<FieldMetadata> => ({
|
||||||
position,
|
position,
|
||||||
fieldId: field.id,
|
fieldId: field.id,
|
||||||
@ -35,7 +25,7 @@ export const formatMetadataFieldAsColumnDefinition = ({
|
|||||||
fieldName: field.name,
|
fieldName: field.name,
|
||||||
placeHolder: field.label,
|
placeHolder: field.label,
|
||||||
},
|
},
|
||||||
Icon: IconBrandLinkedin,
|
Icon: icons[field.icon ?? 'Icon123'],
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
basePathToShowPage: `/object/${metadataObject.nameSingular}/`,
|
basePathToShowPage: `/object/${metadataObject.nameSingular}/`,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -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',
|
||||||
|
});
|
||||||
@ -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'],
|
||||||
|
});
|
||||||
13
front/src/modules/metadata/utils/parseFieldType.ts
Normal file
13
front/src/modules/metadata/utils/parseFieldType.ts
Normal 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;
|
||||||
|
};
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
||||||
import {
|
import {
|
||||||
@ -12,12 +12,14 @@ import { ActivityType, Person } from '~/generated/graphql';
|
|||||||
export const useCreateActivityForPeople = () => {
|
export const useCreateActivityForPeople = () => {
|
||||||
const openCreateActivityRightDrawer =
|
const openCreateActivityRightDrawer =
|
||||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
|
||||||
|
|
||||||
return useRecoilCallback(
|
return useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
(type: ActivityType) => {
|
(type: ActivityType) => {
|
||||||
const relatedEntites: ActivityTargetableEntity[] = [];
|
const relatedEntites: ActivityTargetableEntity[] = [];
|
||||||
|
const selectedRowIds = Object.keys(
|
||||||
|
snapshot.getLoadable(selectedRowIdsSelector).getValue(),
|
||||||
|
);
|
||||||
for (const id of selectedRowIds) {
|
for (const id of selectedRowIds) {
|
||||||
const person = snapshot
|
const person = snapshot
|
||||||
.getLoadable(entityFieldsFamilyState(id))
|
.getLoadable(entityFieldsFamilyState(id))
|
||||||
@ -39,6 +41,6 @@ export const useCreateActivityForPeople = () => {
|
|||||||
relatedEntites,
|
relatedEntites,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[selectedRowIds, openCreateActivityRightDrawer],
|
[openCreateActivityRightDrawer],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,75 +0,0 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
|
||||||
import { selectedRowIdsSelector } from '@/ui/data/data-table/states/selectors/selectedRowIdsSelector';
|
|
||||||
import { tableRowIdsState } from '@/ui/data/data-table/states/tableRowIdsState';
|
|
||||||
import { IconCheckbox, IconNotes, IconTrash } from '@/ui/display/icon';
|
|
||||||
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
|
||||||
import { ActivityType, useDeleteManyPersonMutation } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { GET_PEOPLE } from '../graphql/queries/getPeople';
|
|
||||||
|
|
||||||
import { useCreateActivityForPeople } from './useCreateActivityForPeople';
|
|
||||||
|
|
||||||
export const usePersonTableActionBarEntries = () => {
|
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
|
||||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
|
||||||
const setActionBarEntries = useSetRecoilState(actionBarEntriesState);
|
|
||||||
const createActivityForPeople = useCreateActivityForPeople();
|
|
||||||
|
|
||||||
const resetRowSelection = useResetTableRowSelection();
|
|
||||||
|
|
||||||
const [deleteManyPerson] = useDeleteManyPersonMutation({
|
|
||||||
refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
|
|
||||||
});
|
|
||||||
|
|
||||||
const handleDeleteClick = async () => {
|
|
||||||
const rowIdsToDelete = selectedRowIds;
|
|
||||||
|
|
||||||
resetRowSelection();
|
|
||||||
|
|
||||||
await deleteManyPerson({
|
|
||||||
variables: {
|
|
||||||
ids: rowIdsToDelete,
|
|
||||||
},
|
|
||||||
optimisticResponse: {
|
|
||||||
__typename: 'Mutation',
|
|
||||||
deleteManyPerson: {
|
|
||||||
count: rowIdsToDelete.length,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
update: (cache) => {
|
|
||||||
setTableRowIds(
|
|
||||||
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
|
||||||
);
|
|
||||||
rowIdsToDelete.forEach((id) => {
|
|
||||||
cache.evict({ id: cache.identify({ id, __typename: 'Person' }) });
|
|
||||||
cache.gc();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
setActionBarEntries: () =>
|
|
||||||
setActionBarEntries([
|
|
||||||
{
|
|
||||||
label: 'Note',
|
|
||||||
Icon: IconNotes,
|
|
||||||
onClick: () => createActivityForPeople(ActivityType.Note),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Task',
|
|
||||||
Icon: IconCheckbox,
|
|
||||||
onClick: () => createActivityForPeople(ActivityType.Task),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Delete',
|
|
||||||
Icon: IconTrash,
|
|
||||||
accent: 'danger',
|
|
||||||
onClick: () => handleDeleteClick(),
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||||
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
import { useResetTableRowSelection } from '@/ui/data/data-table/hooks/useResetTableRowSelection';
|
||||||
@ -12,6 +12,7 @@ import {
|
|||||||
IconNotes,
|
IconNotes,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
} from '@/ui/display/icon';
|
} from '@/ui/display/icon';
|
||||||
|
import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionBarEntriesState';
|
||||||
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
|
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
|
||||||
import {
|
import {
|
||||||
ActivityType,
|
ActivityType,
|
||||||
@ -25,38 +26,41 @@ import { useCreateActivityForPeople } from './useCreateActivityForPeople';
|
|||||||
|
|
||||||
export const usePersonTableContextMenuEntries = () => {
|
export const usePersonTableContextMenuEntries = () => {
|
||||||
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
const setContextMenuEntries = useSetRecoilState(contextMenuEntriesState);
|
||||||
|
const setActionBarEntriesState = useSetRecoilState(actionBarEntriesState);
|
||||||
const createActivityForPeople = useCreateActivityForPeople();
|
const createActivityForPeople = useCreateActivityForPeople();
|
||||||
|
|
||||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
const setTableRowIds = useSetRecoilState(tableRowIdsState);
|
||||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
|
||||||
|
|
||||||
const resetRowSelection = useResetTableRowSelection();
|
const resetRowSelection = useResetTableRowSelection();
|
||||||
|
|
||||||
const selectedPersonId = selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
|
||||||
|
|
||||||
const { data } = useGetFavoritesQuery();
|
const { data } = useGetFavoritesQuery();
|
||||||
|
|
||||||
const favorites = data?.findFavorites;
|
const favorites = data?.findFavorites;
|
||||||
|
|
||||||
const isFavorite =
|
|
||||||
!!selectedPersonId &&
|
|
||||||
!!favorites?.find((favorite) => favorite.person?.id === selectedPersonId);
|
|
||||||
|
|
||||||
const { insertPersonFavorite, deletePersonFavorite } = useFavorites();
|
const { insertPersonFavorite, deletePersonFavorite } = useFavorites();
|
||||||
|
|
||||||
const handleFavoriteButtonClick = () => {
|
const handleFavoriteButtonClick = useRecoilCallback(({ snapshot }) => () => {
|
||||||
|
const selectedRowIds = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedPersonId =
|
||||||
|
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedPersonId &&
|
||||||
|
!!favorites?.find((favorite) => favorite.person?.id === selectedPersonId);
|
||||||
|
|
||||||
resetRowSelection();
|
resetRowSelection();
|
||||||
if (isFavorite) deletePersonFavorite(selectedPersonId);
|
if (isFavorite) deletePersonFavorite(selectedPersonId);
|
||||||
else insertPersonFavorite(selectedPersonId);
|
else insertPersonFavorite(selectedPersonId);
|
||||||
};
|
});
|
||||||
|
|
||||||
const [deleteManyPerson] = useDeleteManyPersonMutation({
|
const [deleteManyPerson] = useDeleteManyPersonMutation({
|
||||||
refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
|
refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleDeleteClick = async () => {
|
const handleDeleteClick = useRecoilCallback(({ snapshot }) => async () => {
|
||||||
const rowIdsToDelete = selectedRowIds;
|
const rowIdsToDelete = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
resetRowSelection();
|
resetRowSelection();
|
||||||
|
|
||||||
@ -71,15 +75,28 @@ export const usePersonTableContextMenuEntries = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: () => {
|
update: () => {
|
||||||
setTableRowIds(
|
setTableRowIds((tableRowIds) =>
|
||||||
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setContextMenuEntries: () =>
|
setContextMenuEntries: useRecoilCallback(({ snapshot }) => () => {
|
||||||
|
const selectedRowIds = snapshot
|
||||||
|
.getLoadable(selectedRowIdsSelector)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const selectedPersonId =
|
||||||
|
selectedRowIds.length === 1 ? selectedRowIds[0] : '';
|
||||||
|
|
||||||
|
const isFavorite =
|
||||||
|
!!selectedPersonId &&
|
||||||
|
!!favorites?.find(
|
||||||
|
(favorite) => favorite.person?.id === selectedPersonId,
|
||||||
|
);
|
||||||
|
|
||||||
setContextMenuEntries([
|
setContextMenuEntries([
|
||||||
{
|
{
|
||||||
label: 'New task',
|
label: 'New task',
|
||||||
@ -108,6 +125,27 @@ export const usePersonTableContextMenuEntries = () => {
|
|||||||
accent: 'danger',
|
accent: 'danger',
|
||||||
onClick: () => handleDeleteClick(),
|
onClick: () => handleDeleteClick(),
|
||||||
},
|
},
|
||||||
]),
|
]);
|
||||||
|
}),
|
||||||
|
setActionBarEntries: useRecoilCallback(() => () => {
|
||||||
|
setActionBarEntriesState([
|
||||||
|
{
|
||||||
|
label: 'Task',
|
||||||
|
Icon: IconCheckbox,
|
||||||
|
onClick: () => createActivityForPeople(ActivityType.Task),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Note',
|
||||||
|
Icon: IconNotes,
|
||||||
|
onClick: () => createActivityForPeople(ActivityType.Note),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Delete',
|
||||||
|
Icon: IconTrash,
|
||||||
|
accent: 'danger',
|
||||||
|
onClick: () => handleDeleteClick(),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions';
|
import { peopleAvailableFieldDefinitions } from '@/people/constants/peopleAvailableFieldDefinitions';
|
||||||
import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition';
|
import { getPeopleOptimisticEffectDefinition } from '@/people/graphql/optimistic-effect-definitions/getPeopleOptimisticEffectDefinition';
|
||||||
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
|
|
||||||
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePersonTableContextMenuEntries';
|
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePersonTableContextMenuEntries';
|
||||||
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
||||||
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
||||||
@ -53,8 +52,8 @@ export const PersonTable = () => {
|
|||||||
viewScopeId,
|
viewScopeId,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { setContextMenuEntries } = usePersonTableContextMenuEntries();
|
const { setContextMenuEntries, setActionBarEntries } =
|
||||||
const { setActionBarEntries } = usePersonTableActionBarEntries();
|
usePersonTableContextMenuEntries();
|
||||||
|
|
||||||
const updatePerson = async (variables: UpdateOnePersonMutationVariables) => {
|
const updatePerson = async (variables: UpdateOnePersonMutationVariables) => {
|
||||||
updateEntityMutation({
|
updateEntityMutation({
|
||||||
@ -74,7 +73,6 @@ export const PersonTable = () => {
|
|||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -46,29 +46,6 @@ const PeopleTableEffect = () => {
|
|||||||
setViewObjectId,
|
setViewObjectId,
|
||||||
setViewType,
|
setViewType,
|
||||||
]);
|
]);
|
||||||
// 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 <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -79,6 +79,7 @@ const StyledTableContainer = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type DataTableProps = {
|
type DataTableProps = {
|
||||||
@ -121,20 +122,20 @@ export const DataTable = ({ updateEntityMutation }: DataTableProps) => {
|
|||||||
return (
|
return (
|
||||||
<EntityUpdateMutationContext.Provider value={updateEntityMutation}>
|
<EntityUpdateMutationContext.Provider value={updateEntityMutation}>
|
||||||
<StyledTableWithHeader>
|
<StyledTableWithHeader>
|
||||||
<StyledTableContainer ref={tableBodyRef}>
|
<StyledTableContainer>
|
||||||
<ScrollWrapper>
|
<ScrollWrapper>
|
||||||
<div>
|
<div ref={tableBodyRef}>
|
||||||
<StyledTable className="entity-table-cell">
|
<StyledTable className="entity-table-cell">
|
||||||
<DataTableHeader />
|
<DataTableHeader />
|
||||||
<DataTableBody />
|
<DataTableBody />
|
||||||
</StyledTable>
|
</StyledTable>
|
||||||
|
<DragSelect
|
||||||
|
dragSelectable={tableBodyRef}
|
||||||
|
onDragSelectionStart={resetTableRowSelection}
|
||||||
|
onDragSelectionChange={setRowSelectedState}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ScrollWrapper>
|
</ScrollWrapper>
|
||||||
<DragSelect
|
|
||||||
dragSelectable={tableBodyRef}
|
|
||||||
onDragSelectionStart={resetTableRowSelection}
|
|
||||||
onDragSelectionChange={setRowSelectedState}
|
|
||||||
/>
|
|
||||||
</StyledTableContainer>
|
</StyledTableContainer>
|
||||||
</StyledTableWithHeader>
|
</StyledTableWithHeader>
|
||||||
</EntityUpdateMutationContext.Provider>
|
</EntityUpdateMutationContext.Provider>
|
||||||
|
|||||||
@ -23,10 +23,8 @@ export const DataTableEffect = ({
|
|||||||
getRequestResultKey,
|
getRequestResultKey,
|
||||||
getRequestOptimisticEffectDefinition,
|
getRequestOptimisticEffectDefinition,
|
||||||
|
|
||||||
filterDefinitionArray,
|
|
||||||
setActionBarEntries,
|
setActionBarEntries,
|
||||||
setContextMenuEntries,
|
setContextMenuEntries,
|
||||||
sortDefinitionArray,
|
|
||||||
}: {
|
}: {
|
||||||
useGetRequest: typeof useGetCompaniesQuery | typeof useGetPeopleQuery;
|
useGetRequest: typeof useGetCompaniesQuery | typeof useGetPeopleQuery;
|
||||||
getRequestResultKey: string;
|
getRequestResultKey: string;
|
||||||
@ -59,7 +57,7 @@ export const DataTableEffect = ({
|
|||||||
onCompleted: (data: any) => {
|
onCompleted: (data: any) => {
|
||||||
const entities = data[getRequestResultKey] ?? [];
|
const entities = data[getRequestResultKey] ?? [];
|
||||||
|
|
||||||
setDataTableData(entities, filterDefinitionArray, sortDefinitionArray);
|
setDataTableData(entities);
|
||||||
|
|
||||||
registerOptimisticEffect({
|
registerOptimisticEffect({
|
||||||
variables: { orderBy: sortsOrderBy, where: tablefiltersWhere },
|
variables: { orderBy: sortsOrderBy, where: tablefiltersWhere },
|
||||||
|
|||||||
@ -1,15 +1,10 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
|
import { entityFieldsFamilyState } from '@/ui/data/field/states/entityFieldsFamilyState';
|
||||||
import { FilterDefinition } from '@/ui/data/filter/types/FilterDefinition';
|
|
||||||
import { useRecoilScopeId } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopeId';
|
|
||||||
import { useView } from '@/views/hooks/useView';
|
import { useView } from '@/views/hooks/useView';
|
||||||
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
|
|
||||||
|
|
||||||
import { SortDefinition } from '../../sort/types/SortDefinition';
|
|
||||||
import { isFetchingDataTableDataState } from '../states/isFetchingDataTableDataState';
|
import { isFetchingDataTableDataState } from '../states/isFetchingDataTableDataState';
|
||||||
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
import { numberOfTableRowsState } from '../states/numberOfTableRowsState';
|
||||||
import { TableRecoilScopeContext } from '../states/recoil-scope-contexts/TableRecoilScopeContext';
|
|
||||||
import { tableRowIdsState } from '../states/tableRowIdsState';
|
import { tableRowIdsState } from '../states/tableRowIdsState';
|
||||||
|
|
||||||
import { useResetTableRowSelection } from './useResetTableRowSelection';
|
import { useResetTableRowSelection } from './useResetTableRowSelection';
|
||||||
@ -18,15 +13,9 @@ export const useSetDataTableData = () => {
|
|||||||
const resetTableRowSelection = useResetTableRowSelection();
|
const resetTableRowSelection = useResetTableRowSelection();
|
||||||
const { setEntityCountInCurrentView } = useView();
|
const { setEntityCountInCurrentView } = useView();
|
||||||
|
|
||||||
const tableContextScopeId = useRecoilScopeId(TableRecoilScopeContext);
|
|
||||||
|
|
||||||
return useRecoilCallback(
|
return useRecoilCallback(
|
||||||
({ set, snapshot }) =>
|
({ set, snapshot }) =>
|
||||||
<T extends { id: string }>(
|
<T extends { id: string }>(newEntityArray: T[]) => {
|
||||||
newEntityArray: T[],
|
|
||||||
filterDefinitionArray: FilterDefinition[],
|
|
||||||
sortDefinitionArray: SortDefinition[],
|
|
||||||
) => {
|
|
||||||
for (const entity of newEntityArray) {
|
for (const entity of newEntityArray) {
|
||||||
const currentEntity = snapshot
|
const currentEntity = snapshot
|
||||||
.getLoadable(entityFieldsFamilyState(entity.id))
|
.getLoadable(entityFieldsFamilyState(entity.id))
|
||||||
@ -50,16 +39,9 @@ export const useSetDataTableData = () => {
|
|||||||
resetTableRowSelection();
|
resetTableRowSelection();
|
||||||
|
|
||||||
set(numberOfTableRowsState, entityIds.length);
|
set(numberOfTableRowsState, entityIds.length);
|
||||||
|
|
||||||
setEntityCountInCurrentView(entityIds.length);
|
setEntityCountInCurrentView(entityIds.length);
|
||||||
|
|
||||||
set(
|
|
||||||
availableSortDefinitionsScopedState({ scopeId: tableContextScopeId }),
|
|
||||||
sortDefinitionArray,
|
|
||||||
);
|
|
||||||
|
|
||||||
set(isFetchingDataTableDataState, false);
|
set(isFetchingDataTableDataState, false);
|
||||||
},
|
},
|
||||||
[resetTableRowSelection, setEntityCountInCurrentView, tableContextScopeId],
|
[resetTableRowSelection, setEntityCountInCurrentView],
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,53 @@
|
|||||||
|
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||||
|
import { Field } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { Filter } from '../types/Filter';
|
||||||
|
|
||||||
|
type FilterToTurnIntoWhereClause = Omit<Filter, 'definition'> & {
|
||||||
|
definition: {
|
||||||
|
type: Filter['definition']['type'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const turnFiltersIntoWhereClauseV2 = (
|
||||||
|
filters: FilterToTurnIntoWhereClause[],
|
||||||
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
|
) => {
|
||||||
|
const whereClause: Record<string, any> = {};
|
||||||
|
|
||||||
|
filters.forEach((filter) => {
|
||||||
|
const correspondingField = fields.find(
|
||||||
|
(field) => field.id === filter.fieldId,
|
||||||
|
);
|
||||||
|
if (!correspondingField) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find field ${filter.fieldId} in metadata object`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (filter.definition.type) {
|
||||||
|
case 'text':
|
||||||
|
switch (filter.operand) {
|
||||||
|
case ViewFilterOperand.Contains:
|
||||||
|
whereClause[correspondingField.name] = {
|
||||||
|
eq: filter.value,
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
case ViewFilterOperand.DoesNotContain:
|
||||||
|
whereClause[correspondingField.name] = {
|
||||||
|
not: {
|
||||||
|
eq: filter.value,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown operand ${filter.operand} for ${filter.definition.type} filter`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new Error('Unknown filter type');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return whereClause;
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
|
import { useRecoilScopedStateV2 } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedStateV2';
|
||||||
import { availableSortDefinitionsScopedState } from '@/views/states/availableSortDefinitionsScopedState';
|
|
||||||
|
|
||||||
|
import { availableSortDefinitionsScopedState } from '../states/availableSortDefinitionsScopedState';
|
||||||
import { isSortSelectedScopedState } from '../states/isSortSelectedScopedState';
|
import { isSortSelectedScopedState } from '../states/isSortSelectedScopedState';
|
||||||
|
|
||||||
export const useSortStates = (scopeId: string) => {
|
export const useSortStates = (scopeId: string) => {
|
||||||
|
|||||||
@ -2,7 +2,9 @@ import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScope
|
|||||||
|
|
||||||
import { SortDefinition } from '../types/SortDefinition';
|
import { SortDefinition } from '../types/SortDefinition';
|
||||||
|
|
||||||
export const availableSortsScopedState = createScopedState<SortDefinition[]>({
|
export const availableSortDefinitionsScopedState = createScopedState<
|
||||||
key: 'availableSortsScopedState',
|
SortDefinition[]
|
||||||
|
>({
|
||||||
|
key: 'availableSortDefinitionsScopedState',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
});
|
});
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { Field } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { Sort } from '../types/Sort';
|
||||||
|
|
||||||
|
export const turnSortsIntoOrderByV2 = (
|
||||||
|
sorts: Sort[],
|
||||||
|
fields: Pick<Field, 'id' | 'name'>[],
|
||||||
|
) => {
|
||||||
|
const sortsObject: Record<string, 'AscNullsFirst' | 'DescNullsLast'> = {};
|
||||||
|
sorts.forEach((sort) => {
|
||||||
|
const correspondingField = fields.find(
|
||||||
|
(field) => field.id === sort.fieldId,
|
||||||
|
);
|
||||||
|
if (!correspondingField) {
|
||||||
|
throw new Error(
|
||||||
|
`Could not find field ${sort.fieldId} in metadata object`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const direction =
|
||||||
|
sort.direction === 'asc' ? 'AscNullsFirst' : 'DescNullsLast';
|
||||||
|
|
||||||
|
sortsObject[correspondingField.name] = direction;
|
||||||
|
});
|
||||||
|
|
||||||
|
return sortsObject;
|
||||||
|
};
|
||||||
@ -42,6 +42,7 @@ const StyledWrapper = styled.div`
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries';
|
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
||||||
import { CompanyTableMockMode } from '@/companies/table/components/CompanyTableMockMode';
|
import { CompanyTableMockMode } from '@/companies/table/components/CompanyTableMockMode';
|
||||||
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||||
@ -12,7 +12,7 @@ import { actionBarOpenState } from '../../states/actionBarIsOpenState';
|
|||||||
import { ActionBar } from '../ActionBar';
|
import { ActionBar } from '../ActionBar';
|
||||||
|
|
||||||
const FilledActionBar = (props: { selectedIds: string[] }) => {
|
const FilledActionBar = (props: { selectedIds: string[] }) => {
|
||||||
const { setActionBarEntries } = useCompanyTableActionBarEntries();
|
const { setActionBarEntries } = useCompanyTableContextMenuEntries();
|
||||||
setActionBarEntries();
|
setActionBarEntries();
|
||||||
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
|
const setActionBarOpenState = useSetRecoilState(actionBarOpenState);
|
||||||
setActionBarOpenState(true);
|
setActionBarOpenState(true);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useCreateOneObject } from '@/metadata/hooks/useCreateOneObject';
|
||||||
import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings';
|
import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings';
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
||||||
@ -17,6 +18,7 @@ import { H2Title } from '@/ui/display/typography/components/H2Title';
|
|||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Section } from '@/ui/layout/section/components/Section';
|
import { Section } from '@/ui/layout/section/components/Section';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
export const SettingsNewObject = () => {
|
export const SettingsNewObject = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -29,6 +31,10 @@ export const SettingsNewObject = () => {
|
|||||||
disabledMetadataObjects: disabledObjects,
|
disabledMetadataObjects: disabledObjects,
|
||||||
} = useMetadataObjectForSettings();
|
} = useMetadataObjectForSettings();
|
||||||
|
|
||||||
|
const { createOneObject: createOneView } = useCreateOneObject({
|
||||||
|
objectNamePlural: 'viewsV2',
|
||||||
|
});
|
||||||
|
|
||||||
const [selectedStandardObjectIds, setSelectedStandardObjectIds] = useState<
|
const [selectedStandardObjectIds, setSelectedStandardObjectIds] = useState<
|
||||||
Record<string, boolean>
|
Record<string, boolean>
|
||||||
>({});
|
>({});
|
||||||
@ -60,12 +66,18 @@ export const SettingsNewObject = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (selectedObjectType === 'Custom') {
|
if (selectedObjectType === 'Custom') {
|
||||||
await createObject({
|
const createdObject = await createObject({
|
||||||
labelPlural: customFormValues.labelPlural,
|
labelPlural: customFormValues.labelPlural,
|
||||||
labelSingular: customFormValues.labelSingular,
|
labelSingular: customFormValues.labelSingular,
|
||||||
description: customFormValues.description,
|
description: customFormValues.description,
|
||||||
icon: customFormValues.icon,
|
icon: customFormValues.icon,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await createOneView?.({
|
||||||
|
objectId: createdObject.data?.createOneObject.id,
|
||||||
|
type: ViewType.Table,
|
||||||
|
name: `All ${customFormValues.labelPlural}`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate('/settings/objects');
|
navigate('/settings/objects');
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useCreateOneObject } from '@/metadata/hooks/useCreateOneObject';
|
||||||
|
import { useFindManyObjects } from '@/metadata/hooks/useFindManyObjects';
|
||||||
import { useMetadataField } from '@/metadata/hooks/useMetadataField';
|
import { useMetadataField } from '@/metadata/hooks/useMetadataField';
|
||||||
import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings';
|
import { useMetadataObjectForSettings } from '@/metadata/hooks/useMetadataObjectForSettings';
|
||||||
|
import { PaginatedObjectTypeResults } from '@/metadata/types/PaginatedObjectTypeResults';
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
||||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||||
@ -13,6 +16,8 @@ import { AppPath } from '@/types/AppPath';
|
|||||||
import { IconSettings } from '@/ui/display/icon';
|
import { IconSettings } from '@/ui/display/icon';
|
||||||
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
||||||
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
export const SettingsObjectNewFieldStep2 = () => {
|
export const SettingsObjectNewFieldStep2 = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -36,15 +41,47 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
type: MetadataFieldDataType;
|
type: MetadataFieldDataType;
|
||||||
}>({ icon: 'IconUsers', label: '', type: 'number' });
|
}>({ icon: 'IconUsers', label: '', type: 'number' });
|
||||||
|
|
||||||
if (!activeMetadataObject) return null;
|
const [objectViews, setObjectViews] = useState<View[]>([]);
|
||||||
|
|
||||||
|
const { createOneObject: createOneViewField } = useCreateOneObject({
|
||||||
|
objectNamePlural: 'viewFieldsV2',
|
||||||
|
});
|
||||||
|
|
||||||
|
useFindManyObjects({
|
||||||
|
objectNamePlural: 'viewsV2',
|
||||||
|
filter: {
|
||||||
|
type: { eq: ViewType.Table },
|
||||||
|
objectId: { eq: activeMetadataObject?.id },
|
||||||
|
},
|
||||||
|
onCompleted: async (data: PaginatedObjectTypeResults<View>) => {
|
||||||
|
const views = data.edges;
|
||||||
|
|
||||||
|
if (!views) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setObjectViews(data.edges.map(({ node }) => node));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!activeMetadataObject || !objectViews.length) return null;
|
||||||
|
|
||||||
const canSave = !!formValues.label;
|
const canSave = !!formValues.label;
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
await createMetadataField({
|
const createdField = await createMetadataField({
|
||||||
...formValues,
|
...formValues,
|
||||||
objectId: activeMetadataObject.id,
|
objectId: activeMetadataObject.id,
|
||||||
});
|
});
|
||||||
|
objectViews.forEach(async (view) => {
|
||||||
|
await createOneViewField?.({
|
||||||
|
viewId: view.id,
|
||||||
|
fieldId: createdField.data?.createOneField.id,
|
||||||
|
position: activeMetadataObject.fields.length,
|
||||||
|
isVisible: true,
|
||||||
|
size: 100,
|
||||||
|
});
|
||||||
|
});
|
||||||
navigate(`/settings/objects/${objectSlug}`);
|
navigate(`/settings/objects/${objectSlug}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Command, CommandRunner, Option } from 'nest-commander';
|
import { Command, CommandRunner, Option } from 'nest-commander';
|
||||||
|
|
||||||
import { TenantInitialisationService } from '../tenant-initialisation/tenant-initialisation.service';
|
import { DataSourceMetadataService } from 'src/metadata/data-source-metadata/data-source-metadata.service';
|
||||||
import { DataSourceMetadataService } from '../data-source-metadata/data-source-metadata.service';
|
import { TenantInitialisationService } from 'src/metadata/tenant-initialisation/tenant-initialisation.service';
|
||||||
|
|
||||||
// TODO: implement dry-run
|
// TODO: implement dry-run
|
||||||
interface DataSeedTenantOptions {
|
interface DataSeedTenantOptions {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export class BeforeCreateOneField<T extends FieldMetadata>
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance.input.workspaceId = workspaceId;
|
instance.input.workspaceId = workspaceId;
|
||||||
instance.input.isActive = false;
|
instance.input.isActive = true;
|
||||||
instance.input.isCustom = true;
|
instance.input.isCustom = true;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export class BeforeCreateOneObject<T extends ObjectMetadata>
|
|||||||
instance.input.dataSourceId = lastDataSourceMetadata.id;
|
instance.input.dataSourceId = lastDataSourceMetadata.id;
|
||||||
instance.input.targetTableName = instance.input.namePlural;
|
instance.input.targetTableName = instance.input.namePlural;
|
||||||
instance.input.workspaceId = workspaceId;
|
instance.input.workspaceId = workspaceId;
|
||||||
instance.input.isActive = false;
|
instance.input.isActive = true;
|
||||||
instance.input.isCustom = true;
|
instance.input.isCustom = true;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user