Files
twenty/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectItemTableRow.tsx
T
Félix Malfait 86e4685781 fix: format numbers according to user preferences in settings views (#22501)
## Context

Record and field counts in several settings views were rendered as raw
numbers (e.g. `158355`), ignoring the workspace member's number format
preference. This PR routes them through the existing `useNumberFormat`
hook (which wraps `formatNumber` with the user's `numberFormat`
preference), so they render as `158,355` / `158 355` / `158.355` /
`158'355` depending on the preference.

## Changes

Starting point (from the screenshot): the Settings → Data model objects
table.

- **`SettingsObjectItemTableRow`** — Fields and Records columns in
Settings → Data model
- **`SettingsAvailableStandardObjectItemTableRow`** — Fields column in
Settings → Data model → New object
- **`SettingsDataModelOverviewObject`** — record count next to the
object name in the data model graph overview (guards against `undefined`
while the count query loads)
- **`SettingsLogs`** — "X of Y" record counts above the event logs table
- **`SettingsAdminGeneral`** — Users column in the admin panel top
workspaces table
- **`SettingsAdminWorkspaceContent`** — Members value in the admin panel
workspace info card
- **`NoteList`** — total notes count in the record page Notes tab

## Test coverage

- `npx nx lint:diff-with-main twenty-front` (oxlint + oxfmt) passes
- `npx nx typecheck twenty-front` passes
- No behavioral change beyond formatting; `formatNumber` defaults to 0
decimals so integer counts stay integers

https://claude.ai/code/session_019pXXZSaza8TXPYK8NefQiS

---
_Generated by [Claude
Code](https://claude.ai/code/session_019pXXZSaza8TXPYK8NefQiS)_

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22501?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-07-03 08:28:51 +02:00

92 lines
3.1 KiB
TypeScript

import { styled } from '@linaria/react';
import { useLingui } from '@lingui/react/macro';
import { type ReactNode, useContext } from 'react';
import { useNumberFormat } from '@/localization/hooks/useNumberFormat';
import { ObjectMetadataIcon } from '@/object-metadata/components/ObjectMetadataIcon';
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
import { isHiddenSystemField } from '@/object-metadata/utils/isHiddenSystemField';
import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag';
import { SettingsNameCellSecondaryLabel } from '@/settings/components/SettingsNameCellSecondaryLabel';
import {
SETTINGS_OBJECT_TABLE_ROW_GRID_TEMPLATE_COLUMNS,
StyledActionTableCell,
StyledNameTableCell,
StyledStickyFirstCell,
} from '@/settings/data-model/object-details/components/SettingsObjectItemTableRowStyledComponents';
import { TableCell } from '@/ui/layout/table/components/TableCell';
import { TableRow } from '@/ui/layout/table/components/TableRow';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
export type SettingsObjectMetadataItemTableRowProps = {
action: ReactNode;
objectMetadataItem: EnrichedObjectMetadataItem;
link?: string;
totalObjectCount: number;
};
const StyledNameContainer = styled.div`
align-items: center;
display: flex;
flex: 1;
gap: ${themeCssVariables.spacing[1]};
min-width: 0;
`;
const StyledNameLabel = styled.div`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export const SettingsObjectMetadataItemTableRow = ({
action,
objectMetadataItem,
link,
totalObjectCount,
}: SettingsObjectMetadataItemTableRowProps) => {
const { t } = useLingui();
const { theme } = useContext(ThemeContext);
const { formatNumber } = useNumberFormat();
return (
<TableRow
gridTemplateColumns={SETTINGS_OBJECT_TABLE_ROW_GRID_TEMPLATE_COLUMNS}
key={objectMetadataItem.namePlural}
to={link}
>
<StyledStickyFirstCell>
<StyledNameTableCell>
<ObjectMetadataIcon
objectMetadataItem={objectMetadataItem}
size={theme.icon.size.md}
stroke={theme.icon.stroke.sm}
/>
<StyledNameContainer>
<StyledNameLabel title={objectMetadataItem.labelPlural}>
{objectMetadataItem.labelPlural}
</StyledNameLabel>
{!objectMetadataItem.isActive && (
<SettingsNameCellSecondaryLabel>
{t`Deactivated`}
</SettingsNameCellSecondaryLabel>
)}
</StyledNameContainer>
</StyledNameTableCell>
</StyledStickyFirstCell>
<TableCell>
<SettingsItemTypeTag item={objectMetadataItem} />
</TableCell>
<TableCell align="right">
{formatNumber(
objectMetadataItem.fields.filter(
(field) => !isHiddenSystemField(field),
).length,
)}
</TableCell>
<TableCell align="right">{formatNumber(totalObjectCount)}</TableCell>
<StyledActionTableCell>{action}</StyledActionTableCell>
</TableRow>
);
};