feat: Improved Page and History names (#4908)

Improved page and history names. 
Closes #4684 

---------

Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
This commit is contained in:
Zoltán Völcsey 2024-04-15 14:40:30 +02:00 committed by GitHub
parent 756de8a31b
commit 5477665e5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 108 additions and 18 deletions

View File

@ -1,6 +1,6 @@
export enum SettingsPath {
ProfilePage = 'profile',
Appearance = 'profile/appearance',
Appearance = 'appearance',
Accounts = 'accounts',
NewAccount = 'accounts/new',
AccountsCalendars = 'accounts/calendars',

View File

@ -5,14 +5,17 @@ import { ObjectFilterDropdownButton } from '@/object-record/object-filter-dropdo
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/components/ObjectSortDropdownButton';
import { TopBar } from '@/ui/layout/top-bar/TopBar';
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect';
import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect';
import { ViewBarEffect } from '@/views/components/ViewBarEffect';
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
import { ViewScope } from '@/views/scopes/ViewScope';
import { GraphQLView } from '@/views/types/GraphQLView';
import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDropdown';
import { capitalize } from '~/utils/string/capitalize';
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
@ -34,6 +37,9 @@ export const ViewBar = ({
}: ViewBarProps) => {
const { objectNamePlural } = useParams();
const { currentViewWithCombinedFiltersAndSorts: currentView } =
useGetCurrentView(viewBarId);
const filterDropdownId = 'view-filter';
const sortDropdownId = 'view-sort';
@ -41,6 +47,10 @@ export const ViewBar = ({
return;
}
const pageTitle = currentView?.name
? `${currentView?.name} - ${capitalize(objectNamePlural)}`
: capitalize(objectNamePlural);
return (
<ViewScope
viewScopeId={viewBarId}
@ -52,6 +62,7 @@ export const ViewBar = ({
<QueryParamsFiltersEffect />
<QueryParamsViewIdEffect />
<PageTitle title={pageTitle} />
<TopBar
className={className}
leftComponent={

View File

@ -11,6 +11,7 @@ import {
AnimatedPlaceholderErrorSubTitle,
AnimatedPlaceholderErrorTitle,
} from '@/ui/layout/animated-placeholder/components/ErrorPlaceholderStyled';
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
const StyledBackDrop = styled.div`
align-items: center;
@ -36,6 +37,7 @@ export const NotFound = () => {
return (
<>
<PageTitle title="Page Not Found | Twenty" />
<StyledBackDrop>
<AnimatedPlaceholderErrorContainer>
<AnimatedPlaceholder type="error404" />

View File

@ -9,7 +9,9 @@ import { useSelectedTableCellEditMode } from '@/object-record/record-table/recor
import { PageBody } from '@/ui/layout/page/PageBody';
import { PageContainer } from '@/ui/layout/page/PageContainer';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { RecordIndexPageHeader } from '~/pages/object-record/RecordIndexPageHeader';
import { capitalize } from '~/utils/string/capitalize';
const StyledIndexContainer = styled.div`
display: flex;
@ -40,6 +42,7 @@ export const RecordIndexPage = () => {
return (
<PageContainer>
<PageTitle title={`${capitalize(objectNamePlural)}`} />
<RecordIndexPageHeader createRecord={handleAddButtonClick} />
<PageBody>
<StyledIndexContainer>

View File

@ -18,6 +18,7 @@ import { ShowPageMoreButton } from '@/ui/layout/show-page/components/ShowPageMor
import { PageTitle } from '@/ui/utilities/page-title/PageTitle';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isDefined } from '~/utils/isDefined';
import { capitalize } from '~/utils/string/capitalize';
export const RecordShowPage = () => {
const { objectNameSingular, objectRecordId } = useParams<{
@ -80,13 +81,20 @@ export const RecordShowPage = () => {
const labelIdentifierFieldValue =
record?.[labelIdentifierFieldMetadataItem?.name ?? ''];
const pageName =
labelIdentifierFieldMetadataItem?.type === FieldMetadataType.FullName
? [
labelIdentifierFieldValue?.firstName,
labelIdentifierFieldValue?.lastName,
].join(' ')
: `${labelIdentifierFieldValue}`;
: isDefined(labelIdentifierFieldValue)
? `${labelIdentifierFieldValue}`
: '';
const pageTitle = pageName.trim()
? `${pageName} - ${capitalize(objectNameSingular)}`
: capitalize(objectNameSingular);
// Temporarily since we don't have relations for remote objects yet
if (objectMetadataItem.isRemote) {
@ -95,7 +103,7 @@ export const RecordShowPage = () => {
return (
<PageContainer>
<PageTitle title={pageName} />
<PageTitle title={pageTitle} />
<PageHeader
title={pageName ?? ''}
hasBackButton

View File

@ -1,4 +1,4 @@
import { getPageTitleFromPath } from '../title-utils';
import { getPageTitleFromPath, SettingsPageTitles } from '../title-utils';
describe('title-utils', () => {
it('should return the correct title for a given path', () => {
@ -13,14 +13,39 @@ describe('title-utils', () => {
expect(getPageTitleFromPath('/objects/opportunities')).toBe(
'Opportunities',
);
expect(getPageTitleFromPath('/settings/profile')).toBe('Profile');
expect(getPageTitleFromPath('/settings/profile/appearance')).toBe(
'Appearance',
expect(getPageTitleFromPath('/settings/objects/opportunities')).toBe(
SettingsPageTitles.Objects,
);
expect(getPageTitleFromPath('/settings/profile')).toBe(
SettingsPageTitles.Profile,
);
expect(getPageTitleFromPath('/settings/appearance')).toBe(
SettingsPageTitles.Appearance,
);
expect(getPageTitleFromPath('/settings/accounts')).toBe(
SettingsPageTitles.Accounts,
);
expect(getPageTitleFromPath('/settings/accounts/new')).toBe(
SettingsPageTitles.Accounts,
);
expect(getPageTitleFromPath('/settings/accounts/calendars')).toBe(
SettingsPageTitles.Accounts,
);
expect(
getPageTitleFromPath('/settings/accounts/calendars/:accountUuid'),
).toBe(SettingsPageTitles.Accounts);
expect(getPageTitleFromPath('/settings/accounts/emails')).toBe(
SettingsPageTitles.Accounts,
);
expect(getPageTitleFromPath('/settings/accounts/emails/:accountUuid')).toBe(
SettingsPageTitles.Accounts,
);
expect(getPageTitleFromPath('/settings/workspace-members')).toBe(
'Workspace Members',
SettingsPageTitles.Members,
);
expect(getPageTitleFromPath('/settings/workspace')).toBe(
SettingsPageTitles.General,
);
expect(getPageTitleFromPath('/settings/workspace')).toBe('Workspace');
expect(getPageTitleFromPath('/')).toBe('Twenty');
expect(getPageTitleFromPath('/random')).toBe('Twenty');
});

View File

@ -2,8 +2,41 @@ import { AppBasePath } from '@/types/AppBasePath';
import { AppPath } from '@/types/AppPath';
import { SettingsPath } from '@/types/SettingsPath';
export enum SettingsPageTitles {
Accounts = 'Account - Settings',
Appearance = 'Appearance - Settings',
Profile = 'Profile - Settings',
Objects = 'Data model - Settings',
Members = 'Members - Settings',
Developers = 'Developers - Settings',
Integration = 'Integrations - Settings',
General = 'General - Settings',
Default = 'Settings',
}
enum SettingsPathPrefixes {
Accounts = `${AppBasePath.Settings}/${SettingsPath.Accounts}`,
Appearance = `${AppBasePath.Settings}/${SettingsPath.Appearance}`,
Profile = `${AppBasePath.Settings}/${SettingsPath.ProfilePage}`,
Objects = `${AppBasePath.Settings}/${SettingsPath.Objects}`,
Members = `${AppBasePath.Settings}/${SettingsPath.WorkspaceMembersPage}`,
Developers = `${AppBasePath.Settings}/${SettingsPath.Developers}`,
Integration = `${AppBasePath.Settings}/${SettingsPath.Integrations}`,
General = `${AppBasePath.Settings}/${SettingsPath.Workspace}`,
}
const getPathnameOrPrefix = (pathname: string) => {
for (const prefix of Object.values(SettingsPathPrefixes)) {
if (pathname.startsWith(prefix)) {
return prefix;
}
}
return pathname;
};
export const getPageTitleFromPath = (pathname: string): string => {
switch (pathname) {
const pathnameOrPrefix = getPathnameOrPrefix(pathname);
switch (pathnameOrPrefix) {
case AppPath.Verify:
return 'Verify';
case AppPath.SignInUp:
@ -18,14 +51,22 @@ export const getPageTitleFromPath = (pathname: string): string => {
return 'Tasks';
case AppPath.OpportunitiesPage:
return 'Opportunities';
case `${AppBasePath.Settings}/${SettingsPath.ProfilePage}`:
return 'Profile';
case `${AppBasePath.Settings}/${SettingsPath.Appearance}`:
return 'Appearance';
case `${AppBasePath.Settings}/${SettingsPath.WorkspaceMembersPage}`:
return 'Workspace Members';
case `${AppBasePath.Settings}/${SettingsPath.Workspace}`:
return 'Workspace';
case SettingsPathPrefixes.Appearance:
return SettingsPageTitles.Appearance;
case SettingsPathPrefixes.Accounts:
return SettingsPageTitles.Accounts;
case SettingsPathPrefixes.Profile:
return SettingsPageTitles.Profile;
case SettingsPathPrefixes.Members:
return SettingsPageTitles.Members;
case SettingsPathPrefixes.Objects:
return SettingsPageTitles.Objects;
case SettingsPathPrefixes.Developers:
return SettingsPageTitles.Developers;
case SettingsPathPrefixes.Integration:
return SettingsPageTitles.Integration;
case SettingsPathPrefixes.General:
return SettingsPageTitles.General;
default:
return 'Twenty';
}