Files
twenty/packages/twenty-front/src/modules/command-menu/components/CommandMenu.tsx
T
Charles Bochet bc4ae35bc4 Rework atom naming (#18240)
## Summary

- **Enhanced the `matching-state-variable` ESLint rule** to enforce
consistent naming for `ComponentState`, `FamilyState`, and
`ComponentFamilyState` hooks — previously it only covered `useAtomState`
and `useAtomStateValue`
- **The rule now checks 12 hooks** across three categories: value hooks
(`useAtomComponentStateValue`, `useAtomFamilyStateValue`, etc.), state
hooks (`useAtomComponentState`, `useAtomComponentFamilyState`), and
setter hooks (`useSetAtomState`, `useSetAtomComponentState`,
`useSetAtomFamilyState`, `useSetAtomComponentFamilyState`)
- **Fixed all 225 resulting lint violations** across 151 files, renaming
variables to match their state atom names (e.g. `currentViewId` →
`contextStoreCurrentViewId`, `selectedRecord` → `recordStore`). Cases
where the same state is accessed with different family keys/instance IDs
are suppressed with `eslint-disable-next-line`.

## Naming convention

| Hook | State argument | Valid | Invalid |
|------|---------------|-------|---------|
| `useAtomStateValue` | `fooState` | `const foo = ...` | `const bar =
...` |
| `useAtomComponentStateValue` | `fooComponentState` | `const foo = ...`
| `const bar = ...` |
| `useAtomFamilyStateValue` | `fooFamilyState` | `const foo = ...` |
`const bar = ...` |
| `useAtomComponentFamilyStateValue` | `fooComponentFamilyState` |
`const foo = ...` | `const bar = ...` |
| `useAtomState` | `fooState` | `const [foo, setFoo] = ...` | `const
[bar, setBar] = ...` |
| `useAtomComponentState` | `fooComponentState` | `const [foo, setFoo] =
...` | `const [bar, setBar] = ...` |
| `useAtomComponentFamilyState` | `fooComponentFamilyState` | `const
[foo, setFoo] = ...` | `const [bar, setBar] = ...` |
| `useSetAtomState` | `fooState` | `const setFoo = ...` | `const setBar
= ...` |
| `useSetAtomComponentState` | `fooComponentState` | `const setFoo =
...` | `const setBar = ...` |
| `useSetAtomFamilyState` | `fooFamilyState` | `const setFoo = ...` |
`const setBar = ...` |
| `useSetAtomComponentFamilyState` | `fooComponentFamilyState` | `const
setFoo = ...` | `const setBar = ...` |
2026-02-25 22:28:25 +01:00

106 lines
3.9 KiB
TypeScript

import { type ActionConfig } from '@/action-menu/actions/types/ActionConfig';
import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { CommandMenuList } from '@/command-menu/components/CommandMenuList';
import { ResetContextToSelectionCommandButton } from '@/command-menu/components/ResetContextToSelectionCommandButton';
import { RESET_CONTEXT_TO_SELECTION } from '@/command-menu/constants/ResetContextToSelection';
import { useMatchingCommandMenuActions } from '@/command-menu/hooks/useMatchingCommandMenuActions';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { useLingui } from '@lingui/react/macro';
import { isDefined } from 'twenty-shared/utils';
export type ActionGroupConfig = {
heading: string;
items?: ActionConfig[];
};
export const CommandMenu = () => {
const { t } = useLingui();
const commandMenuSearch = useAtomStateValue(commandMenuSearchState);
const { objectMetadataItems } = useObjectMetadataItems();
const {
noResults,
matchingStandardActionRecordSelectionActions,
matchingStandardActionObjectActions,
matchingWorkflowRunRecordSelectionActions,
matchingFrontComponentRecordSelectionActions,
matchingStandardActionGlobalActions,
matchingWorkflowRunGlobalActions,
matchingFrontComponentGlobalActions,
matchingNavigateActions,
fallbackActions,
matchingCreateRelatedRecordActions,
} = useMatchingCommandMenuActions({
commandMenuSearch,
});
// eslint-disable-next-line twenty/matching-state-variable
const previousContextStoreCurrentObjectMetadataItemId =
useAtomComponentStateValue(
contextStoreCurrentObjectMetadataItemIdComponentState,
'command-menu-previous',
);
const contextStoreCurrentObjectMetadataItemId = useAtomComponentStateValue(
contextStoreCurrentObjectMetadataItemIdComponentState,
);
const currentObjectMetadataItem = objectMetadataItems.find(
(item) => item.id === contextStoreCurrentObjectMetadataItemId,
);
const commandGroups: ActionGroupConfig[] = [
{
heading: t`Record Selection`,
items: matchingStandardActionRecordSelectionActions
.concat(matchingWorkflowRunRecordSelectionActions)
.concat(matchingFrontComponentRecordSelectionActions),
},
{
heading: t`Create Related Record`,
items: matchingCreateRelatedRecordActions,
},
{
heading: currentObjectMetadataItem?.labelPlural ?? t`Object`,
items: matchingStandardActionObjectActions,
},
{
heading: t`Global`,
items: matchingStandardActionGlobalActions
.concat(matchingWorkflowRunGlobalActions)
.concat(matchingFrontComponentGlobalActions)
.concat(matchingNavigateActions),
},
{
heading: t`Search ''${commandMenuSearch}'' with...`,
items: fallbackActions,
},
];
const selectableItems = commandGroups.flatMap((group) => group.items ?? []);
const selectableItemIds = selectableItems.map((item) => item.key);
if (isDefined(previousContextStoreCurrentObjectMetadataItemId)) {
selectableItemIds.unshift(RESET_CONTEXT_TO_SELECTION);
}
return (
<CommandMenuList
commandGroups={commandGroups}
selectableItemIds={selectableItemIds}
noResults={noResults}
>
{isDefined(previousContextStoreCurrentObjectMetadataItemId) && (
<CommandGroup heading={t`Context`}>
<ResetContextToSelectionCommandButton />
</CommandGroup>
)}
</CommandMenuList>
);
};