New useNavigateApp (#9729)

Todo : 
- replace all instances of useNavigate(
- remove getSettingsPagePath
- add eslint rule to enfore usage of useNavigateApp instead of
useNavigate
This commit is contained in:
Félix Malfait
2025-01-18 13:58:12 +01:00
committed by GitHub
parent 8572471973
commit 152902d1be
115 changed files with 975 additions and 679 deletions

View File

@ -1,17 +1,14 @@
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
import { SettingsPath } from '@/types/SettingsPath';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import {
useLocation,
useNavigate,
useParams,
useSearchParams,
} from 'react-router-dom';
import { useLocation, useParams, useSearchParams } from 'react-router-dom';
import { Button, IconChevronDown, isDefined, MenuItem } from 'twenty-ui';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
const StyledContainer = styled.div`
align-items: center;
@ -66,7 +63,7 @@ const StyledButton = styled(Button)`
export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
const dropdownId = `settings-object-new-field-breadcrumb-dropdown`;
const { closeDropdown } = useDropdown(dropdownId);
const navigate = useNavigate();
const navigate = useNavigateSettings();
const location = useLocation();
const { objectNamePlural = '' } = useParams();
const [searchParams] = useSearchParams();
@ -78,11 +75,15 @@ export const SettingsDataModelNewFieldBreadcrumbDropDown = () => {
const handleClick = (step: 'select' | 'configure') => {
if (step === 'configure' && isDefined(fieldType)) {
navigate(
`/settings/objects/${objectNamePlural}/new-field/configure?fieldType=${fieldType}`,
SettingsPath.ObjectNewFieldConfigure,
{ objectNamePlural },
{ fieldType },
);
} else {
navigate(
`/settings/objects/${objectNamePlural}/new-field/select${fieldType ? `?fieldType=${fieldType}` : ''}`,
SettingsPath.ObjectNewFieldSelect,
{ objectNamePlural },
fieldType ? { fieldType } : undefined,
);
}
closeDropdown();

View File

@ -8,6 +8,7 @@ import { useBooleanSettingsFormInitialValues } from '@/settings/data-model/field
import { useCurrencySettingsFormInitialValues } from '@/settings/data-model/fields/forms/currency/hooks/useCurrencySettingsFormInitialValues';
import { useSelectSettingsFormInitialValues } from '@/settings/data-model/fields/forms/select/hooks/useSelectSettingsFormInitialValues';
import { SettingsFieldType } from '@/settings/data-model/types/SettingsFieldType';
import { SettingsPath } from '@/types/SettingsPath';
import { TextInput } from '@/ui/input/components/TextInput';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
@ -17,6 +18,7 @@ import { Controller, useFormContext } from 'react-hook-form';
import { H2Title, IconSearch, UndecoratedLink } from 'twenty-ui';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { SettingsDataModelFieldTypeFormValues } from '~/pages/settings/data-model/SettingsObjectNewField/SettingsObjectNewFieldSelect';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
type SettingsObjectNewFieldSelectorProps = {
className?: string;
@ -128,7 +130,15 @@ export const SettingsObjectNewFieldSelector = ({
.map(([key, config]) => (
<StyledCardContainer key={key}>
<UndecoratedLink
to={`/settings/objects/${objectNamePlural}/new-field/configure?fieldType=${key}`}
to={getSettingsPath(
SettingsPath.ObjectNewFieldConfigure,
{
objectNamePlural,
},
{
fieldType: key,
},
)}
fullWidth
onClick={() => {
setValue('type', key as SettingsFieldType);

View File

@ -13,8 +13,10 @@ import { capitalize } from 'twenty-shared';
import { FieldMetadataType } from '~/generated/graphql';
import { ObjectFieldRowWithoutRelation } from '@/settings/data-model/graph-overview/components/SettingsDataModelOverviewFieldWithoutRelation';
import { SettingsPath } from '@/types/SettingsPath';
import '@xyflow/react/dist/style.css';
import { useState } from 'react';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
type SettingsDataModelOverviewObjectNode = Node<ObjectMetadataItem, 'object'>;
type SettingsDataModelOverviewObjectProps =
@ -122,7 +124,9 @@ export const SettingsDataModelOverviewObject = ({
<StyledHeader>
<StyledObjectName onMouseEnter={() => {}} onMouseLeave={() => {}}>
<StyledObjectLink
to={`/settings/objects/${objectMetadataItem.namePlural}`}
to={getSettingsPath(SettingsPath.Objects, {
objectNamePlural: objectMetadataItem.namePlural,
})}
>
{Icon && <Icon size={theme.icon.size.md} />}
{capitalize(objectMetadataItem.namePlural)}

View File

@ -12,6 +12,7 @@ import { SettingsObjectFieldActiveActionDropdown } from '@/settings/data-model/o
import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown';
import { settingsObjectFieldsFamilyState } from '@/settings/data-model/object-details/states/settingsObjectFieldsFamilyState';
import { isFieldTypeSupportedInSettings } from '@/settings/data-model/utils/isFieldTypeSupportedInSettings';
import { SettingsPath } from '@/types/SettingsPath';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
@ -19,7 +20,6 @@ import { View } from '@/views/types/View';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import {
IconMinus,
@ -30,7 +30,9 @@ import {
useIcons,
} from 'twenty-ui';
import { RelationDefinitionType } from '~/generated-metadata/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { SettingsObjectDetailTableItem } from '~/pages/settings/data-model/types/SettingsObjectDetailTableItem';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { RELATION_TYPES } from '../../constants/RelationTypes';
import { SettingsObjectFieldDataType } from './SettingsObjectFieldDataType';
@ -72,7 +74,7 @@ export const SettingsObjectFieldItemTableRow = ({
const variant = objectMetadataItem.isCustom ? 'identifier' : 'field-type';
const navigate = useNavigate();
const navigate = useNavigateSettings();
const [navigationMemorizedUrl, setNavigationMemorizedUrl] = useRecoilState(
navigationMemorizedUrlState,
@ -108,7 +110,10 @@ export const SettingsObjectFieldItemTableRow = ({
!isLabelIdentifier &&
LABEL_IDENTIFIER_FIELD_METADATA_TYPES.includes(fieldMetadataItem.type);
const linkToNavigate = `./${fieldMetadataItem.name}`;
const linkToNavigate = getSettingsPath(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
fieldName: fieldMetadataItem.name,
});
const {
activateMetadataField,
@ -212,7 +217,15 @@ export const SettingsObjectFieldItemTableRow = ({
return (
<StyledObjectFieldTableRow
onClick={mode === 'view' ? () => navigate(linkToNavigate) : undefined}
onClick={
mode === 'view'
? () =>
navigate(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
fieldName: fieldMetadataItem.name,
})
: undefined
}
>
<UndecoratedLink to={linkToNavigate}>
<StyledNameTableCell>
@ -244,7 +257,9 @@ export const SettingsObjectFieldItemTableRow = ({
}
to={
isRelatedObjectLinkable
? `/settings/objects/${relationObjectMetadataItem.namePlural}`
? getSettingsPath(SettingsPath.Objects, {
objectNamePlural: relationObjectMetadataItem.namePlural,
})
: undefined
}
value={fieldType}
@ -261,7 +276,12 @@ export const SettingsObjectFieldItemTableRow = ({
<SettingsObjectFieldActiveActionDropdown
isCustomField={fieldMetadataItem.isCustom === true}
scopeKey={fieldMetadataItem.id}
onEdit={() => navigate(linkToNavigate)}
onEdit={() =>
navigate(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
fieldName: fieldMetadataItem.name,
})
}
onSetAsLabelIdentifier={
canBeSetAsLabelIdentifier
? () => handleSetLabelIdentifierField(fieldMetadataItem)
@ -286,7 +306,12 @@ export const SettingsObjectFieldItemTableRow = ({
<SettingsObjectFieldInactiveActionDropdown
isCustomField={fieldMetadataItem.isCustom === true}
scopeKey={fieldMetadataItem.id}
onEdit={() => navigate(linkToNavigate)}
onEdit={() =>
navigate(SettingsPath.ObjectFieldEdit, {
objectNamePlural: objectMetadataItem.namePlural,
fieldName: fieldMetadataItem.name,
})
}
onActivate={() =>
activateMetadataField(fieldMetadataItem.id, objectMetadataItem.id)
}

View File

@ -2,7 +2,6 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { zodResolver } from '@hookform/resolvers/zod';
import { FormProvider, useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { Button, H2Title, IconArchive, Section } from 'twenty-ui';
import { z, ZodError } from 'zod';
@ -18,7 +17,7 @@ import {
import { settingsDataModelObjectIdentifiersFormSchema } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm';
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
import { settingsUpdateObjectInputSchema } from '@/settings/data-model/validation-schemas/settingsUpdateObjectInputSchema';
import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
@ -27,8 +26,10 @@ import styled from '@emotion/styled';
import isEmpty from 'lodash.isempty';
import pick from 'lodash.pick';
import { useSetRecoilState } from 'recoil';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { updatedObjectNamePluralState } from '~/pages/settings/data-model/states/updatedObjectNamePluralState';
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
import { getAppPath } from '~/utils/navigation/getAppPath';
const objectEditFormSchema = z
.object({})
@ -54,7 +55,7 @@ const StyledFormSection = styled(Section)`
`;
export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
const navigate = useNavigate();
const navigate = useNavigateSettings();
const { enqueueSnackBar } = useSnackBar();
const setUpdatedObjectNamePlural = useSetRecoilState(
updatedObjectNamePluralState,
@ -65,8 +66,6 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
useLastVisitedObjectMetadataItem();
const { getLastVisitedViewIdFromObjectMetadataItemId } = useLastVisitedView();
const settingsObjectsPagePath = getSettingsPagePath(SettingsPath.Objects);
const formConfig = useForm<SettingsDataModelObjectEditFormValues>({
mode: 'onTouched',
resolver: zodResolver(objectEditFormSchema),
@ -147,11 +146,17 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
objectMetadataItem.id,
);
setNavigationMemorizedUrl(
`/objects/${objectNamePluralForRedirection}?view=${lastVisitedView}`,
getAppPath(
AppPath.RecordIndexPage,
{ objectNamePlural: objectNamePluralForRedirection },
{ viewId: lastVisitedView },
),
);
}
navigate(`${settingsObjectsPagePath}/${objectNamePluralForRedirection}`);
navigate(SettingsPath.ObjectDetail, {
objectNamePlural: objectNamePluralForRedirection,
});
} catch (error) {
if (error instanceof ZodError) {
enqueueSnackBar(error.issues[0].message, {
@ -170,7 +175,7 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
idToUpdate: objectMetadataItem.id,
updatePayload: { isActive: false },
});
navigate(settingsObjectsPagePath);
navigate(SettingsPath.Objects);
};
return (