Feat/metadata datatable types (#2175)
* Handled new url v2 type * Fixed refetch queries * wip * Ok delete but views bug * Fix lint --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,110 +0,0 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { isFlexibleBackendEnabledState } from '@/client-config/states/isFlexibleBackendEnabledState';
|
||||
import { MetadataObjectsQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
import { FIND_MANY_METADATA_OBJECTS } from '../graphql/queries';
|
||||
import { useApolloMetadataClient } from '../hooks/useApolloMetadataClient';
|
||||
import { useCreateOneObject } from '../hooks/useCreateOneObject';
|
||||
import { useFindManyObjects } from '../hooks/useFindManyObjects';
|
||||
import { useSeedCustomObjectsTemp } from '../hooks/useSeedCustomObjectsTemp';
|
||||
import { metadataObjectsState } from '../states/metadataObjectsState';
|
||||
import { MetadataObject } from '../types/MetadataObject';
|
||||
|
||||
export const FetchMetadataEffect = () => {
|
||||
const [metadataObjects, setMetadataObjects] =
|
||||
useRecoilState(metadataObjectsState);
|
||||
const [isFlexibleBackendEnabled] = useRecoilState(
|
||||
isFlexibleBackendEnabledState,
|
||||
);
|
||||
const apolloMetadataClient = useApolloMetadataClient();
|
||||
|
||||
const seedCustomObjectsTemp = useSeedCustomObjectsTemp();
|
||||
|
||||
const { createOneObject } = useCreateOneObject({
|
||||
objectNamePlural: 'suppliers',
|
||||
});
|
||||
|
||||
const { objects: suppliers, loading } = useFindManyObjects({
|
||||
objectNamePlural: 'suppliers',
|
||||
});
|
||||
|
||||
const [created, setCreated] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!created && !loading && suppliers.length === 0 && createOneObject) {
|
||||
createOneObject({
|
||||
name: 'Supplier 1',
|
||||
city: 'City 1',
|
||||
});
|
||||
|
||||
createOneObject({
|
||||
name: 'Supplier 2',
|
||||
city: 'City 2',
|
||||
});
|
||||
|
||||
createOneObject({
|
||||
name: 'Supplier 3',
|
||||
city: 'City 3',
|
||||
});
|
||||
|
||||
setCreated(true);
|
||||
}
|
||||
}, [suppliers, createOneObject, loading, created]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isFlexibleBackendEnabled) return;
|
||||
|
||||
(async () => {
|
||||
if (apolloMetadataClient && metadataObjects.length === 0) {
|
||||
const objects = await apolloMetadataClient.query<MetadataObjectsQuery>({
|
||||
query: FIND_MANY_METADATA_OBJECTS,
|
||||
});
|
||||
|
||||
if (
|
||||
objects.data.objects.edges.length > 0 &&
|
||||
metadataObjects.length === 0
|
||||
) {
|
||||
const formattedObjects: MetadataObject[] =
|
||||
objects.data.objects.edges.map((object) => ({
|
||||
...object.node,
|
||||
fields: object.node.fields.edges.map((field) => field.node),
|
||||
}));
|
||||
setMetadataObjects(formattedObjects);
|
||||
} else if (
|
||||
objects.data.objects.edges.length === 0 &&
|
||||
metadataObjects.length === 0
|
||||
) {
|
||||
try {
|
||||
await seedCustomObjectsTemp();
|
||||
|
||||
const objects =
|
||||
await apolloMetadataClient.query<MetadataObjectsQuery>({
|
||||
query: FIND_MANY_METADATA_OBJECTS,
|
||||
});
|
||||
|
||||
const formattedObjects: MetadataObject[] =
|
||||
objects.data.objects.edges.map((object) => ({
|
||||
...object.node,
|
||||
fields: object.node.fields.edges.map((field) => field.node),
|
||||
}));
|
||||
|
||||
setMetadataObjects(formattedObjects);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, [
|
||||
isFlexibleBackendEnabled,
|
||||
metadataObjects,
|
||||
setMetadataObjects,
|
||||
apolloMetadataClient,
|
||||
seedCustomObjectsTemp,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -1,29 +1,58 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { IconArchive } from '@/ui/display/icon';
|
||||
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
||||
import { Button } from '@/ui/input/button/components/Button';
|
||||
import { IconButton } from '@/ui/input/button/components/IconButton';
|
||||
import NavItem from '@/ui/navigation/navbar/components/NavItem';
|
||||
import { useGetClientConfigQuery } from '~/generated/graphql';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
|
||||
import { useCreateNewTempsCustomObject } from '../hooks/useCreateNewTempCustomObject';
|
||||
import { useDeleteOneMetadataObject } from '../hooks/useDeleteOneMetadataObject';
|
||||
import { useFindManyMetadataObjects } from '../hooks/useFindManyMetadataObjects';
|
||||
|
||||
export const MetadataObjectNavItems = () => {
|
||||
const { data } = useGetClientConfigQuery();
|
||||
|
||||
const { metadataObjects } = useFindManyMetadataObjects();
|
||||
|
||||
const isFlexibleBackendEnabled = data?.clientConfig?.flexibleBackendEnabled;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log({
|
||||
metadataObjects,
|
||||
});
|
||||
|
||||
if (!isFlexibleBackendEnabled) return <></>;
|
||||
const createNewTempCustomObject = useCreateNewTempsCustomObject();
|
||||
|
||||
const { deleteOneMetadataObject } = useDeleteOneMetadataObject();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<>
|
||||
{metadataObjects.map((metadataObject) => (
|
||||
<NavItem
|
||||
key={metadataObject.id}
|
||||
label={capitalize(metadataObject.namePlural)}
|
||||
to={`/objects/${metadataObject.namePlural}`}
|
||||
Icon={IconBuildingSkyscraper}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
title="+ Create new object"
|
||||
variant="secondary"
|
||||
onClick={createNewTempCustomObject}
|
||||
/>
|
||||
{metadataObjects
|
||||
.filter((metadataObject) => !!metadataObject.isActive)
|
||||
.map((metadataObject) => (
|
||||
<div style={{ display: 'flex', flexDirection: 'row', width: '60%' }}>
|
||||
<IconButton
|
||||
Icon={IconArchive}
|
||||
onClick={() => {
|
||||
deleteOneMetadataObject(metadataObject.id);
|
||||
}}
|
||||
/>
|
||||
<NavItem
|
||||
key={metadataObject.id}
|
||||
label={capitalize(metadataObject.namePlural)}
|
||||
to={`/objects/${metadataObject.namePlural}`}
|
||||
Icon={IconBuildingSkyscraper}
|
||||
onClick={() => {
|
||||
navigate(`/objects/${metadataObject.namePlural}`);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@ -21,15 +21,17 @@ export const ObjectDataTableEffect = ({
|
||||
}: ObjectDataTableEffectProps) => {
|
||||
const setDataTableData = useSetObjectDataTableData();
|
||||
|
||||
const { objects } = useFindManyObjects({
|
||||
const { objects, loading } = useFindManyObjects({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const entities = objects ?? [];
|
||||
if (!loading) {
|
||||
const entities = objects ?? [];
|
||||
|
||||
setDataTableData(entities);
|
||||
}, [objects, setDataTableData]);
|
||||
setDataTableData(entities);
|
||||
}
|
||||
}, [objects, setDataTableData, loading]);
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const tableRecoilScopeId = useRecoilScopeId(TableRecoilScopeContext);
|
||||
@ -61,8 +63,10 @@ export const ObjectDataTableEffect = ({
|
||||
const viewId = searchParams.get('view');
|
||||
if (viewId) {
|
||||
handleViewSelect(viewId);
|
||||
} else {
|
||||
handleViewSelect(objectNamePlural);
|
||||
}
|
||||
}, [handleViewSelect, searchParams]);
|
||||
}, [handleViewSelect, searchParams, objectNamePlural]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { suppliersAvailableColumnDefinitions } from '@/companies/constants/companiesAvailableColumnDefinitions';
|
||||
import { DataTable } from '@/ui/data/data-table/components/DataTable';
|
||||
import { TableContext } from '@/ui/data/data-table/contexts/TableContext';
|
||||
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import { ViewBarContext } from '@/ui/data/view-bar/contexts/ViewBarContext';
|
||||
import { useTableViews } from '@/views/hooks/useTableViews';
|
||||
|
||||
import { useMetadataTableViews } from '../hooks/useMetadataTableViews';
|
||||
import { useUpdateOneObject } from '../hooks/useUpdateOneObject';
|
||||
import { MetadataObjectIdentifier } from '../types/MetadataObjectIdentifier';
|
||||
|
||||
@ -14,10 +13,7 @@ export type ObjectTableProps = MetadataObjectIdentifier;
|
||||
|
||||
export const ObjectTable = ({ objectNamePlural }: ObjectTableProps) => {
|
||||
const { createView, deleteView, submitCurrentView, updateView } =
|
||||
useTableViews({
|
||||
objectId: 'company',
|
||||
columnDefinitions: suppliersAvailableColumnDefinitions,
|
||||
});
|
||||
useMetadataTableViews();
|
||||
|
||||
const { updateOneObject } = useUpdateOneObject({
|
||||
objectNamePlural,
|
||||
|
||||
76
front/src/modules/metadata/components/ObjectTablePage.tsx
Normal file
76
front/src/modules/metadata/components/ObjectTablePage.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ObjectTable } from '@/metadata/components/ObjectTable';
|
||||
import { MetadataObjectIdentifier } from '@/metadata/types/MetadataObjectIdentifier';
|
||||
import { DataTableActionBar } from '@/ui/data/data-table/action-bar/components/DataTableActionBar';
|
||||
import { DataTableContextMenu } from '@/ui/data/data-table/context-menu/components/DataTableContextMenu';
|
||||
import { TableRecoilScopeContext } from '@/ui/data/data-table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
||||
import { PageAddButton } from '@/ui/layout/page/PageAddButton';
|
||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
||||
import { PageHotkeysEffect } from '@/ui/layout/page/PageHotkeysEffect';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
|
||||
import { useCreateOneObject } from '../hooks/useCreateOneObject';
|
||||
import { useFindOneMetadataObject } from '../hooks/useFindOneMetadataObject';
|
||||
import { MetadataObjectScope } from '../scopes/MetadataObjectScope';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export type ObjectTablePageProps = MetadataObjectIdentifier;
|
||||
|
||||
export const ObjectTablePage = () => {
|
||||
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||
|
||||
const { objectNotFoundInMetadata, loading } = useFindOneMetadataObject({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && objectNotFoundInMetadata) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [objectNotFoundInMetadata, loading, navigate]);
|
||||
|
||||
const { createOneObject } = useCreateOneObject({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const handleAddButtonClick = async () => {
|
||||
createOneObject?.({
|
||||
name: 'Test',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader title="Objects" Icon={IconBuildingSkyscraper}>
|
||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
||||
<PageAddButton onClick={handleAddButtonClick} />
|
||||
</PageHeader>
|
||||
<PageBody>
|
||||
<RecoilScope
|
||||
scopeId={objectNamePlural}
|
||||
CustomRecoilScopeContext={TableRecoilScopeContext}
|
||||
>
|
||||
<StyledTableContainer>
|
||||
<MetadataObjectScope metadataObjectNamePlural={objectNamePlural}>
|
||||
<ObjectTable objectNamePlural={objectNamePlural} />
|
||||
</MetadataObjectScope>
|
||||
</StyledTableContainer>
|
||||
<DataTableActionBar />
|
||||
<DataTableContextMenu />
|
||||
</RecoilScope>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user