Migrate to a monorepo structure (#2909)
This commit is contained in:
@ -0,0 +1,272 @@
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { CompanyTeam } from '@/companies/components/CompanyTeam';
|
||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition';
|
||||
import { FieldContext } from '@/object-record/field/contexts/FieldContext';
|
||||
import { entityFieldsFamilyState } from '@/object-record/field/states/entityFieldsFamilyState';
|
||||
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
|
||||
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
|
||||
import { InlineCellHotkeyScope } from '@/object-record/record-inline-cell/types/InlineCellHotkeyScope';
|
||||
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||
import { filterAvailableFieldMetadataItem } from '@/object-record/utils/filterAvailableFieldMetadataItem';
|
||||
import { IconBuildingSkyscraper } from '@/ui/display/icon';
|
||||
import { PageBody } from '@/ui/layout/page/PageBody';
|
||||
import { PageContainer } from '@/ui/layout/page/PageContainer';
|
||||
import { PageFavoriteButton } from '@/ui/layout/page/PageFavoriteButton';
|
||||
import { PageHeader } from '@/ui/layout/page/PageHeader';
|
||||
import { ShowPageContainer } from '@/ui/layout/page/ShowPageContainer';
|
||||
import { ShowPageAddButton } from '@/ui/layout/show-page/components/ShowPageAddButton';
|
||||
import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer';
|
||||
import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer';
|
||||
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
|
||||
import { ShowPageRecoilScopeContext } from '@/ui/layout/states/ShowPageRecoilScopeContext';
|
||||
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { FileFolder, useUploadImageMutation } from '~/generated/graphql';
|
||||
import { getLogoUrlFromDomainName } from '~/utils';
|
||||
|
||||
import { useFindOneRecord } from '../hooks/useFindOneRecord';
|
||||
import { useUpdateOneRecord } from '../hooks/useUpdateOneRecord';
|
||||
|
||||
export const RecordShowPage = () => {
|
||||
const { objectNameSingular, objectRecordId } = useParams<{
|
||||
objectNameSingular: string;
|
||||
objectRecordId: string;
|
||||
}>();
|
||||
|
||||
if (!objectNameSingular) {
|
||||
throw new Error(`Object name is not defined`);
|
||||
}
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { identifiersMapper } = useRelationPicker();
|
||||
|
||||
const { favorites, createFavorite, deleteFavorite } = useFavorites({
|
||||
objectNamePlural: objectMetadataItem.namePlural,
|
||||
});
|
||||
|
||||
const [, setEntityFields] = useRecoilState(
|
||||
entityFieldsFamilyState(objectRecordId ?? ''),
|
||||
);
|
||||
|
||||
const { record } = useFindOneRecord({
|
||||
objectRecordId,
|
||||
objectNameSingular,
|
||||
onCompleted: (data) => {
|
||||
setEntityFields(data);
|
||||
},
|
||||
});
|
||||
|
||||
const [uploadImage] = useUploadImageMutation();
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const objectMetadataType =
|
||||
objectMetadataItem?.nameSingular === 'company'
|
||||
? 'Company'
|
||||
: objectMetadataItem?.nameSingular === 'person'
|
||||
? 'Person'
|
||||
: 'Custom';
|
||||
|
||||
const useUpdateOneObjectRecordMutation: () => [
|
||||
(params: any) => any,
|
||||
any,
|
||||
] = () => {
|
||||
const updateEntity = ({
|
||||
variables,
|
||||
}: {
|
||||
variables: {
|
||||
where: { id: string };
|
||||
data: {
|
||||
[fieldName: string]: any;
|
||||
};
|
||||
};
|
||||
}) => {
|
||||
updateOneRecord?.({
|
||||
idToUpdate: variables.where.id,
|
||||
input: variables.data,
|
||||
});
|
||||
};
|
||||
|
||||
return [updateEntity, { loading: false }];
|
||||
};
|
||||
|
||||
const isFavorite = objectNameSingular
|
||||
? favorites.some((favorite) => favorite.recordId === record?.id)
|
||||
: false;
|
||||
|
||||
const handleFavoriteButtonClick = async () => {
|
||||
if (!objectNameSingular || !record) return;
|
||||
if (isFavorite) deleteFavorite(record?.id);
|
||||
else {
|
||||
const additionalData =
|
||||
objectNameSingular === 'person'
|
||||
? {
|
||||
labelIdentifier:
|
||||
record.name.firstName + ' ' + record.name.lastName,
|
||||
avatarUrl: record.avatarUrl,
|
||||
avatarType: 'rounded',
|
||||
link: `/object/personV2/${record.id}`,
|
||||
recordId: record.id,
|
||||
}
|
||||
: objectNameSingular === 'company'
|
||||
? {
|
||||
labelIdentifier: record.name,
|
||||
avatarUrl: getLogoUrlFromDomainName(record.domainName ?? ''),
|
||||
avatarType: 'squared',
|
||||
link: `/object/companyV2/${record.id}`,
|
||||
recordId: record.id,
|
||||
}
|
||||
: {};
|
||||
createFavorite(record.id, additionalData);
|
||||
}
|
||||
};
|
||||
|
||||
if (!record) return <></>;
|
||||
|
||||
const pageName =
|
||||
objectNameSingular === 'person'
|
||||
? record.name.firstName + ' ' + record.name.lastName
|
||||
: record.name;
|
||||
|
||||
const recordIdentifiers = identifiersMapper?.(
|
||||
record,
|
||||
objectMetadataItem?.nameSingular ?? '',
|
||||
);
|
||||
|
||||
const onUploadPicture = async (file: File) => {
|
||||
if (objectNameSingular !== 'person') {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await uploadImage({
|
||||
variables: {
|
||||
file,
|
||||
fileFolder: FileFolder.PersonPicture,
|
||||
},
|
||||
});
|
||||
|
||||
const avatarUrl = result?.data?.uploadImage;
|
||||
|
||||
if (!avatarUrl) {
|
||||
return;
|
||||
}
|
||||
if (!updateOneRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
await updateOneRecord({
|
||||
idToUpdate: record?.id,
|
||||
input: {
|
||||
avatarUrl,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageTitle title={pageName} />
|
||||
<PageHeader
|
||||
title={pageName ?? ''}
|
||||
hasBackButton
|
||||
Icon={IconBuildingSkyscraper}
|
||||
>
|
||||
{objectMetadataType !== 'Custom' && (
|
||||
<>
|
||||
<PageFavoriteButton
|
||||
isFavorite={isFavorite}
|
||||
onClick={handleFavoriteButtonClick}
|
||||
/>
|
||||
<ShowPageAddButton
|
||||
key="add"
|
||||
entity={{
|
||||
id: record.id,
|
||||
type: objectMetadataType,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</PageHeader>
|
||||
<PageBody>
|
||||
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
||||
<ShowPageContainer>
|
||||
<ShowPageLeftContainer>
|
||||
<ShowPageSummaryCard
|
||||
id={record.id}
|
||||
logoOrAvatar={recordIdentifiers?.avatarUrl}
|
||||
title={recordIdentifiers?.name ?? 'No name'}
|
||||
date={record.createdAt ?? ''}
|
||||
renderTitleEditComponent={() => <></>}
|
||||
avatarType={recordIdentifiers?.avatarType ?? 'rounded'}
|
||||
onUploadPicture={
|
||||
objectNameSingular === 'person' ? onUploadPicture : undefined
|
||||
}
|
||||
/>
|
||||
<PropertyBox extraPadding={true}>
|
||||
{objectMetadataItem &&
|
||||
[...objectMetadataItem.fields]
|
||||
.sort((a, b) =>
|
||||
a.name === 'name' ? -1 : a.name.localeCompare(b.name),
|
||||
)
|
||||
.filter(filterAvailableFieldMetadataItem)
|
||||
.map((metadataField, index) => {
|
||||
return (
|
||||
<FieldContext.Provider
|
||||
key={record.id + metadataField.id}
|
||||
value={{
|
||||
entityId: record.id,
|
||||
recoilScopeId: record.id + metadataField.id,
|
||||
isLabelIdentifier: false,
|
||||
fieldDefinition:
|
||||
formatFieldMetadataItemAsColumnDefinition({
|
||||
field: metadataField,
|
||||
position: index,
|
||||
objectMetadataItem,
|
||||
}),
|
||||
useUpdateEntityMutation:
|
||||
useUpdateOneObjectRecordMutation,
|
||||
hotkeyScope: InlineCellHotkeyScope.InlineCell,
|
||||
}}
|
||||
>
|
||||
<RecordInlineCell />
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
})}
|
||||
</PropertyBox>
|
||||
{objectNameSingular === 'company' ? (
|
||||
<>
|
||||
<CompanyTeam company={record} />
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</ShowPageLeftContainer>
|
||||
<ShowPageRightContainer
|
||||
entity={{
|
||||
id: record.id,
|
||||
// TODO: refacto
|
||||
type:
|
||||
objectMetadataItem?.nameSingular === 'company'
|
||||
? 'Company'
|
||||
: objectMetadataItem?.nameSingular === 'person'
|
||||
? 'Person'
|
||||
: 'Custom',
|
||||
}}
|
||||
timeline
|
||||
tasks
|
||||
notes
|
||||
emails
|
||||
/>
|
||||
</ShowPageContainer>
|
||||
</RecoilScope>
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,124 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { RecordTable } from '@/object-record/record-table/components/RecordTable';
|
||||
import { TableOptionsDropdownId } from '@/object-record/record-table/constants/TableOptionsDropdownId';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { TableOptionsDropdown } from '@/object-record/record-table/options/components/TableOptionsDropdown';
|
||||
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
||||
import { SpreadsheetImportProvider } from '@/spreadsheet-import/provider/components/SpreadsheetImportProvider';
|
||||
import { ViewBar } from '@/views/components/ViewBar';
|
||||
import { mapViewFieldsToColumnDefinitions } from '@/views/utils/mapViewFieldsToColumnDefinitions';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { mapViewSortsToSorts } from '@/views/utils/mapViewSortsToSorts';
|
||||
|
||||
import { RecordTableEffect } from './RecordTableEffect';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
`;
|
||||
|
||||
export const RecordTableContainer = ({
|
||||
objectNamePlural,
|
||||
createRecord,
|
||||
}: {
|
||||
objectNamePlural: string;
|
||||
createRecord: () => void;
|
||||
}) => {
|
||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { columnDefinitions } =
|
||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { openPersonSpreadsheetImport } = useSpreadsheetPersonImport();
|
||||
const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
|
||||
|
||||
const recordTableId = objectNamePlural ?? '';
|
||||
const viewBarId = objectNamePlural ?? '';
|
||||
|
||||
const { setTableFilters, setTableSorts, setTableColumns } = useRecordTable({
|
||||
recordTableScopeId: recordTableId,
|
||||
});
|
||||
|
||||
const updateEntity = ({
|
||||
variables,
|
||||
}: {
|
||||
variables: {
|
||||
where: { id: string };
|
||||
data: {
|
||||
[fieldName: string]: any;
|
||||
};
|
||||
};
|
||||
}) => {
|
||||
updateOneRecord?.({
|
||||
idToUpdate: variables.where.id,
|
||||
input: variables.data,
|
||||
});
|
||||
};
|
||||
|
||||
const handleImport = () => {
|
||||
const openImport =
|
||||
recordTableId === 'companies'
|
||||
? openCompanySpreadsheetImport
|
||||
: openPersonSpreadsheetImport;
|
||||
openImport();
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<SpreadsheetImportProvider>
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
optionsDropdownButton={
|
||||
<TableOptionsDropdown
|
||||
recordTableId={recordTableId}
|
||||
onImport={
|
||||
['companies', 'people'].includes(recordTableId)
|
||||
? handleImport
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
}
|
||||
optionsDropdownScopeId={TableOptionsDropdownId}
|
||||
onViewFieldsChange={(viewFields) => {
|
||||
setTableColumns(
|
||||
mapViewFieldsToColumnDefinitions(viewFields, columnDefinitions),
|
||||
);
|
||||
}}
|
||||
onViewFiltersChange={(viewFilters) => {
|
||||
setTableFilters(mapViewFiltersToFilters(viewFilters));
|
||||
}}
|
||||
onViewSortsChange={(viewSorts) => {
|
||||
setTableSorts(mapViewSortsToSorts(viewSorts));
|
||||
}}
|
||||
/>
|
||||
</SpreadsheetImportProvider>
|
||||
<RecordTableEffect recordTableId={recordTableId} viewBarId={viewBarId} />
|
||||
{
|
||||
<RecordTable
|
||||
recordTableId={recordTableId}
|
||||
viewBarId={viewBarId}
|
||||
updateRecordMutation={updateEntity}
|
||||
createRecord={createRecord}
|
||||
/>
|
||||
}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,111 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/useColumnDefinitionsFromFieldMetadata';
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useRecordTableContextMenuEntries } from '@/object-record/hooks/useRecordTableContextMenuEntries';
|
||||
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||
import { filterAvailableTableColumns } from '@/object-record/utils/filterAvailableTableColumns';
|
||||
import { useViewBar } from '@/views/hooks/useViewBar';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
|
||||
export const RecordTableEffect = ({
|
||||
recordTableId,
|
||||
viewBarId,
|
||||
}: {
|
||||
recordTableId: string;
|
||||
viewBarId: string;
|
||||
}) => {
|
||||
const {
|
||||
// Todo: do not infer objectNamePlural from recordTableId
|
||||
scopeId: objectNamePlural,
|
||||
setAvailableTableColumns,
|
||||
setOnEntityCountChange,
|
||||
setObjectMetadataConfig,
|
||||
} = useRecordTable({ recordTableScopeId: recordTableId });
|
||||
|
||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const {
|
||||
objectMetadataItem,
|
||||
basePathToShowPage,
|
||||
labelIdentifierFieldMetadataId,
|
||||
} = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const { columnDefinitions, filterDefinitions, sortDefinitions } =
|
||||
useColumnDefinitionsFromFieldMetadata(objectMetadataItem);
|
||||
|
||||
const {
|
||||
setAvailableSortDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
setAvailableFieldDefinitions,
|
||||
setViewType,
|
||||
setViewObjectMetadataId,
|
||||
setEntityCountInCurrentView,
|
||||
} = useViewBar({ viewBarId });
|
||||
|
||||
useEffect(() => {
|
||||
if (basePathToShowPage && labelIdentifierFieldMetadataId) {
|
||||
setObjectMetadataConfig?.({
|
||||
basePathToShowPage,
|
||||
labelIdentifierFieldMetadataId,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
basePathToShowPage,
|
||||
objectMetadataItem,
|
||||
labelIdentifierFieldMetadataId,
|
||||
setObjectMetadataConfig,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!objectMetadataItem) {
|
||||
return;
|
||||
}
|
||||
setViewObjectMetadataId?.(objectMetadataItem.id);
|
||||
setViewType?.(ViewType.Table);
|
||||
|
||||
setAvailableSortDefinitions?.(sortDefinitions);
|
||||
setAvailableFilterDefinitions?.(filterDefinitions);
|
||||
setAvailableFieldDefinitions?.(columnDefinitions);
|
||||
|
||||
const availableTableColumns = columnDefinitions.filter(
|
||||
filterAvailableTableColumns,
|
||||
);
|
||||
|
||||
setAvailableTableColumns(availableTableColumns);
|
||||
}, [
|
||||
setViewObjectMetadataId,
|
||||
setViewType,
|
||||
columnDefinitions,
|
||||
setAvailableSortDefinitions,
|
||||
setAvailableFilterDefinitions,
|
||||
setAvailableFieldDefinitions,
|
||||
objectMetadataItem,
|
||||
sortDefinitions,
|
||||
filterDefinitions,
|
||||
setAvailableTableColumns,
|
||||
]);
|
||||
|
||||
const { setActionBarEntries, setContextMenuEntries } =
|
||||
useRecordTableContextMenuEntries({
|
||||
recordTableScopeId: recordTableId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setActionBarEntries?.();
|
||||
setContextMenuEntries?.();
|
||||
}, [setActionBarEntries, setContextMenuEntries]);
|
||||
|
||||
useEffect(() => {
|
||||
setOnEntityCountChange(
|
||||
() => (entityCount: number) => setEntityCountInCurrentView(entityCount),
|
||||
);
|
||||
}, [setEntityCountInCurrentView, setOnEntityCountChange]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -0,0 +1,89 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { RecordTableActionBar } from '@/object-record/record-table/action-bar/components/RecordTableActionBar';
|
||||
import { RecordTableContextMenu } from '@/object-record/record-table/context-menu/components/RecordTableContextMenu';
|
||||
import { useLazyLoadIcons } from '@/ui/input/hooks/useLazyLoadIcons';
|
||||
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 { RecordTableContainer } from './RecordTableContainer';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const RecordTablePage = () => {
|
||||
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||
|
||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { icons } = useLazyLoadIcons();
|
||||
|
||||
const { findObjectMetadataItemByNamePlural } =
|
||||
useObjectMetadataItemForSettings();
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isNonEmptyString(objectNamePlural) &&
|
||||
onboardingStatus === OnboardingStatus.Completed
|
||||
) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [objectNamePlural, navigate, onboardingStatus]);
|
||||
|
||||
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
const handleAddButtonClick = async () => {
|
||||
await createOneObject?.({});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageHeader
|
||||
title={
|
||||
objectNamePlural.charAt(0).toUpperCase() + objectNamePlural.slice(1)
|
||||
}
|
||||
Icon={
|
||||
icons[
|
||||
findObjectMetadataItemByNamePlural(objectNamePlural)!.icon ??
|
||||
'Icon123'
|
||||
]
|
||||
}
|
||||
>
|
||||
<PageHotkeysEffect onAddButtonClick={handleAddButtonClick} />
|
||||
<PageAddButton onClick={handleAddButtonClick} />
|
||||
</PageHeader>
|
||||
<PageBody>
|
||||
<StyledTableContainer>
|
||||
<RecordTableContainer
|
||||
objectNamePlural={objectNamePlural}
|
||||
createRecord={handleAddButtonClick}
|
||||
/>
|
||||
</StyledTableContainer>
|
||||
<RecordTableActionBar />
|
||||
<RecordTableContextMenu />
|
||||
</PageBody>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user