1ceeb68da8
[#4422](https://github.com/twentyhq/twenty/issues/4422) Demo: https://github.com/twentyhq/twenty/assets/155670906/f8027ab2-c579-45f7-9f08-f4441a346ae7 Within the demo, we show the various areas in which the Command/CTRL + Click functionality works. The table cells within the People and Companies tab open within both the current tab and new tab due to unchanged functionality within RecordTableCell. We did this to ensure we could get a PR within by the end of the week. In this commit, we ONLY edited EntityChip.tsx. We did this by: - Removing useNavigate() and handleLinkClick/onClick functionality - Wrapping InnerEntityChip in an anchor tag This allowed for Command/CTRL + Click functionality to work. Clickable left cells on tables, left side menu, and data model navigation files/areas DID NOT get updated. --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
194 lines
7.0 KiB
TypeScript
194 lines
7.0 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
import styled from '@emotion/styled';
|
|
import { IconMinus, IconPlus, IconSettings } from 'twenty-ui';
|
|
|
|
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
|
import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField';
|
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
|
import { SettingsHeaderContainer } from '@/settings/components/SettingsHeaderContainer';
|
|
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
|
import {
|
|
SettingsObjectFieldItemTableRow,
|
|
StyledObjectFieldTableRow,
|
|
} from '@/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow';
|
|
import { AppPath } from '@/types/AppPath';
|
|
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
|
import { Button } from '@/ui/input/button/components/Button';
|
|
import { LightIconButton } from '@/ui/input/button/components/LightIconButton';
|
|
import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer';
|
|
import { Section } from '@/ui/layout/section/components/Section';
|
|
import { Table } from '@/ui/layout/table/components/Table';
|
|
import { TableHeader } from '@/ui/layout/table/components/TableHeader';
|
|
import { TableSection } from '@/ui/layout/table/components/TableSection';
|
|
import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
|
|
|
const StyledSection = styled(Section)`
|
|
display: flex;
|
|
flex-direction: column;
|
|
`;
|
|
|
|
const StyledAddCustomFieldButton = styled(Button)`
|
|
align-self: flex-end;
|
|
margin-top: ${({ theme }) => theme.spacing(2)};
|
|
`;
|
|
|
|
export const SettingsObjectNewFieldStep1 = () => {
|
|
const navigate = useNavigate();
|
|
|
|
const { objectSlug = '' } = useParams();
|
|
const { findActiveObjectMetadataItemBySlug } =
|
|
useFilteredObjectMetadataItems();
|
|
|
|
const activeObjectMetadataItem =
|
|
findActiveObjectMetadataItemBySlug(objectSlug);
|
|
|
|
const { activateMetadataField, deactivateMetadataField } =
|
|
useFieldMetadataItem();
|
|
const [metadataFields, setMetadataFields] = useState(
|
|
activeObjectMetadataItem?.fields ?? [],
|
|
);
|
|
|
|
const activeMetadataFields = metadataFields.filter((field) => field.isActive);
|
|
const deactivatedMetadataFields = metadataFields.filter(
|
|
(field) => !field.isActive,
|
|
);
|
|
|
|
const canSave = metadataFields.some(
|
|
(field, index) =>
|
|
field.isActive !== activeObjectMetadataItem?.fields[index].isActive,
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (!activeObjectMetadataItem) {
|
|
navigate(AppPath.NotFound);
|
|
return;
|
|
}
|
|
|
|
if (!metadataFields.length)
|
|
setMetadataFields(activeObjectMetadataItem.fields);
|
|
}, [activeObjectMetadataItem, metadataFields.length, navigate]);
|
|
|
|
if (!activeObjectMetadataItem) return null;
|
|
|
|
const handleToggleField = (fieldMetadataId: string) =>
|
|
setMetadataFields((previousFields) =>
|
|
previousFields.map((field) =>
|
|
field.id === fieldMetadataId
|
|
? { ...field, isActive: !field.isActive }
|
|
: field,
|
|
),
|
|
);
|
|
|
|
const handleSave = async () => {
|
|
await Promise.all(
|
|
metadataFields.map((metadataField, index) => {
|
|
if (
|
|
metadataField.isActive ===
|
|
activeObjectMetadataItem.fields[index].isActive
|
|
) {
|
|
return undefined;
|
|
}
|
|
|
|
return metadataField.isActive
|
|
? activateMetadataField(metadataField)
|
|
: deactivateMetadataField(metadataField);
|
|
}),
|
|
);
|
|
|
|
navigate(`/settings/objects/${objectSlug}`);
|
|
};
|
|
|
|
return (
|
|
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
|
<SettingsPageContainer>
|
|
<SettingsHeaderContainer>
|
|
<Breadcrumb
|
|
links={[
|
|
{ children: 'Objects', href: '/settings/objects' },
|
|
{
|
|
children: activeObjectMetadataItem.labelPlural,
|
|
href: `/settings/objects/${objectSlug}`,
|
|
},
|
|
{ children: 'New Field' },
|
|
]}
|
|
/>
|
|
{!activeObjectMetadataItem.isRemote && (
|
|
<SaveAndCancelButtons
|
|
isSaveDisabled={!canSave}
|
|
onCancel={() => navigate(`/settings/objects/${objectSlug}`)}
|
|
onSave={handleSave}
|
|
/>
|
|
)}
|
|
</SettingsHeaderContainer>
|
|
<StyledSection>
|
|
<H2Title
|
|
title="Check deactivated fields"
|
|
description="Before creating a custom field, check if it already exists in the deactivated section."
|
|
/>
|
|
<Table>
|
|
<StyledObjectFieldTableRow>
|
|
<TableHeader>Name</TableHeader>
|
|
<TableHeader>Field type</TableHeader>
|
|
<TableHeader>Data type</TableHeader>
|
|
<TableHeader></TableHeader>
|
|
</StyledObjectFieldTableRow>
|
|
{!!activeMetadataFields.length && (
|
|
<TableSection isInitiallyExpanded={false} title="Active">
|
|
{activeMetadataFields.map((activeMetadataField) => (
|
|
<SettingsObjectFieldItemTableRow
|
|
key={activeMetadataField.id}
|
|
fieldMetadataItem={activeMetadataField}
|
|
isRemoteObjectField={activeObjectMetadataItem.isRemote}
|
|
ActionIcon={
|
|
isLabelIdentifierField({
|
|
fieldMetadataItem: activeMetadataField,
|
|
objectMetadataItem: activeObjectMetadataItem,
|
|
}) ? undefined : (
|
|
<LightIconButton
|
|
Icon={IconMinus}
|
|
accent="tertiary"
|
|
onClick={() =>
|
|
handleToggleField(activeMetadataField.id)
|
|
}
|
|
/>
|
|
)
|
|
}
|
|
/>
|
|
))}
|
|
</TableSection>
|
|
)}
|
|
{!!deactivatedMetadataFields.length && (
|
|
<TableSection title="Disabled">
|
|
{deactivatedMetadataFields.map((deactivatedMetadataField) => (
|
|
<SettingsObjectFieldItemTableRow
|
|
key={deactivatedMetadataField.name}
|
|
fieldMetadataItem={deactivatedMetadataField}
|
|
ActionIcon={
|
|
<LightIconButton
|
|
Icon={IconPlus}
|
|
accent="tertiary"
|
|
onClick={() =>
|
|
handleToggleField(deactivatedMetadataField.id)
|
|
}
|
|
/>
|
|
}
|
|
/>
|
|
))}
|
|
</TableSection>
|
|
)}
|
|
</Table>
|
|
<StyledAddCustomFieldButton
|
|
Icon={IconPlus}
|
|
title="Add Custom Field"
|
|
size="small"
|
|
variant="secondary"
|
|
to={`/settings/objects/${objectSlug}/new-field/step-2`}
|
|
/>
|
|
</StyledSection>
|
|
</SettingsPageContainer>
|
|
</SubMenuTopBarContainer>
|
|
);
|
|
};
|