Skip to content

Commit cbbcff6

Browse files
gitstart-app[bot]gitstart-twentyv1b3mToledodev
authored
TWNTY-3794 - ESLint rule: only take explicit boolean predicates in if statements (twentyhq#4354)
* ESLint rule: only take explicit boolean predicates in if statements Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Merge main Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Fix frontend linter errors Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Fix jest Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Refactor according to review Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Refactor according to review Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> * Fix lint on new code Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]> --------- Co-authored-by: gitstart-twenty <[email protected]> Co-authored-by: v1b3m <[email protected]> Co-authored-by: Toledodev <[email protected]>
1 parent 8c13b80 commit cbbcff6

File tree

164 files changed

+655
-367
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

164 files changed

+655
-367
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@
241241
"@types/supertest": "^2.0.11",
242242
"@types/uuid": "^9.0.2",
243243
"@typescript-eslint/eslint-plugin": "^6.10.0",
244+
"@typescript-eslint/experimental-utils": "^5.62.0",
244245
"@typescript-eslint/parser": "^6.10.0",
245246
"@typescript-eslint/utils": "^6.9.1",
246247
"@vitejs/plugin-react-swc": "^3.5.0",

packages/twenty-front/.eslintrc.cjs

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ module.exports = {
2222
'**/*config.js',
2323
'codegen*',
2424
'tsup.ui.index.tsx',
25+
'__mocks__',
2526
],
2627
rules: {
2728
'no-restricted-imports': [
@@ -48,6 +49,7 @@ module.exports = {
4849
'@nx/workspace-styled-components-prefixed-with-styled': 'error',
4950
'@nx/workspace-no-state-useref': 'error',
5051
'@nx/workspace-component-props-naming': 'error',
52+
'@nx/workspace-explicit-boolean-predicates-in-if': 'error',
5153
'@nx/workspace-use-getLoadable-and-getValue-to-get-atoms': 'error',
5254

5355
'react/no-unescaped-entities': 'off',
@@ -75,7 +77,7 @@ module.exports = {
7577
{
7678
files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
7779
parserOptions: {
78-
project: ['packages/twenty-front/tsconfig.*?.json'],
80+
project: ['packages/twenty-front/tsconfig.{json,*.json}'],
7981
},
8082
rules: {},
8183
},

packages/twenty-front/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"lint:ci": "yarn lint --config .eslintrc-ci.cjs",
1818
"fmt:fix": "prettier --cache --write \"src/**/*.ts\" \"src/**/*.tsx\"",
1919
"fmt": "prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"",
20-
"test": "jest",
20+
"test": "jest src/modules/spreadsheet-import/utils/__tests__/dataMutations.test.ts",
2121
"test-watch": "jest --watch",
2222
"tsup": "tsup",
2323
"coverage": "jest --coverage",

packages/twenty-front/src/effect-components/PageChangeEffect.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { IconCheckbox } from '@/ui/display/icon';
1818
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
1919
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
2020
import { useGetWorkspaceFromInviteHashLazyQuery } from '~/generated/graphql';
21+
import { isNonNullable } from '~/utils/isNonNullable';
22+
import { isNullable } from '~/utils/isNullable';
2123

2224
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
2325

@@ -81,13 +83,13 @@ export const PageChangeEffect = () => {
8183
) {
8284
navigate(AppPath.SignIn);
8385
} else if (
84-
onboardingStatus &&
86+
isNonNullable(onboardingStatus) &&
8587
onboardingStatus === OnboardingStatus.Incomplete &&
8688
!isMatchingLocation(AppPath.PlanRequired)
8789
) {
8890
navigate(AppPath.PlanRequired);
8991
} else if (
90-
onboardingStatus &&
92+
isNonNullable(onboardingStatus) &&
9193
[OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes(
9294
onboardingStatus,
9395
) &&
@@ -122,7 +124,7 @@ export const PageChangeEffect = () => {
122124
inviteHash,
123125
},
124126
onCompleted: (data) => {
125-
if (!data.findWorkspaceFromInviteHash) {
127+
if (isNullable(data.findWorkspaceFromInviteHash)) {
126128
navigateToSignUp();
127129
}
128130
},

packages/twenty-front/src/modules/activities/blocks/FileBlock.tsx

+7-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@ import {
88
} from '@blocknote/core';
99
import { createReactBlockSpec } from '@blocknote/react';
1010
import styled from '@emotion/styled';
11+
import { isNonEmptyString } from '@sniptt/guards';
1112

1213
import { Button } from '@/ui/input/button/components/Button';
1314
import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider';
15+
import { isNonNullable } from '~/utils/isNonNullable';
16+
import { isNullable } from '~/utils/isNullable';
1417

1518
import { AttachmentIcon } from '../files/components/AttachmentIcon';
1619
import { AttachmentType } from '../files/types/Attachment';
@@ -77,7 +80,7 @@ const FileBlockRenderer = ({
7780
const inputFileRef = useRef<HTMLInputElement>(null);
7881

7982
const handleUploadAttachment = async (file: File) => {
80-
if (!file) {
83+
if (isNullable(file)) {
8184
return '';
8285
}
8386
const fileUrl = await editor.uploadFile?.(file);
@@ -93,10 +96,11 @@ const FileBlockRenderer = ({
9396
inputFileRef?.current?.click?.();
9497
};
9598
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
96-
if (e.target.files) handleUploadAttachment?.(e.target.files[0]);
99+
if (isNonNullable(e.target.files))
100+
handleUploadAttachment?.(e.target.files[0]);
97101
};
98102

99-
if (block.props.url) {
103+
if (isNonEmptyString(block.props.url)) {
100104
return (
101105
<AppThemeProvider>
102106
<StyledFileLine>

packages/twenty-front/src/modules/activities/calendar/utils/sortCalendarEvents.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
2+
import { isNonNullable } from '~/utils/isNonNullable';
23
import { sortAsc } from '~/utils/sort';
34

45
export const sortCalendarEventsAsc = (
@@ -10,7 +11,11 @@ export const sortCalendarEventsAsc = (
1011
calendarEventB.startsAt.getTime(),
1112
);
1213

13-
if (startsAtSort === 0 && calendarEventA.endsAt && calendarEventB.endsAt) {
14+
if (
15+
startsAtSort === 0 &&
16+
isNonNullable(calendarEventA.endsAt) &&
17+
isNonNullable(calendarEventB.endsAt)
18+
) {
1419
return sortAsc(
1520
calendarEventA.endsAt.getTime(),
1621
calendarEventB.endsAt.getTime(),

packages/twenty-front/src/modules/activities/components/ActivityBodyEditor.tsx

+10-8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
2525
import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey';
2626
import { REACT_APP_SERVER_BASE_URL } from '~/config';
2727
import { FileFolder, useUploadFileMutation } from '~/generated/graphql';
28+
import { isNonNullable } from '~/utils/isNonNullable';
29+
import { isNullable } from '~/utils/isNullable';
2830

2931
import { blockSpecs } from '../blocks/blockSpecs';
3032
import { getSlashMenu } from '../blocks/slashMenu';
@@ -78,7 +80,7 @@ export const ActivityBodyEditor = ({
7880
const { upsertActivity } = useUpsertActivity();
7981

8082
const persistBodyDebounced = useDebouncedCallback((newBody: string) => {
81-
if (activity) {
83+
if (isNonNullable(activity)) {
8284
upsertActivity({
8385
activity,
8486
input: {
@@ -90,7 +92,7 @@ export const ActivityBodyEditor = ({
9092

9193
const persistTitleAndBodyDebounced = useDebouncedCallback(
9294
(newTitle: string, newBody: string) => {
93-
if (activity) {
95+
if (isNonNullable(activity)) {
9496
upsertActivity({
9597
activity,
9698
input: {
@@ -124,7 +126,7 @@ export const ActivityBodyEditor = ({
124126
const [uploadFile] = useUploadFileMutation();
125127

126128
const handleUploadAttachment = async (file: File): Promise<string> => {
127-
if (!file) {
129+
if (isNullable(file)) {
128130
return '';
129131
}
130132
const result = await uploadFile({
@@ -226,7 +228,7 @@ export const ActivityBodyEditor = ({
226228
if (isNonEmptyString(activityBody) && activityBody !== '{}') {
227229
return JSON.parse(activityBody);
228230
} else if (
229-
activity &&
231+
isNonNullable(activity) &&
230232
isNonEmptyString(activity.body) &&
231233
activity?.body !== '{}'
232234
) {
@@ -251,7 +253,7 @@ export const ActivityBodyEditor = ({
251253
const handleImagePaste = async (event: ClipboardEvent) => {
252254
const clipboardItems = event.clipboardData?.items;
253255

254-
if (clipboardItems) {
256+
if (isNonNullable(clipboardItems)) {
255257
for (let i = 0; i < clipboardItems.length; i++) {
256258
if (clipboardItems[i].kind === 'file') {
257259
const isImage = clipboardItems[i].type.match('^image/');
@@ -266,7 +268,7 @@ export const ActivityBodyEditor = ({
266268
return;
267269
}
268270

269-
if (isImage) {
271+
if (isNonNullable(isImage)) {
270272
editor?.insertBlocks(
271273
[
272274
{
@@ -332,7 +334,7 @@ export const ActivityBodyEditor = ({
332334
const currentBlockContent = blockIdentifier?.content;
333335

334336
if (
335-
currentBlockContent &&
337+
isNonNullable(currentBlockContent) &&
336338
isArray(currentBlockContent) &&
337339
currentBlockContent.length === 0
338340
) {
@@ -344,7 +346,7 @@ export const ActivityBodyEditor = ({
344346
}
345347

346348
if (
347-
currentBlockContent &&
349+
isNonNullable(currentBlockContent) &&
348350
isArray(currentBlockContent) &&
349351
currentBlockContent[0] &&
350352
currentBlockContent[0].type === 'text'

packages/twenty-front/src/modules/activities/components/ActivityBodyEffect.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRecoilState } from 'recoil';
33

44
import { activityBodyFamilyState } from '@/activities/states/activityBodyFamilyState';
55
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
6+
import { isNonNullable } from '~/utils/isNonNullable';
67

78
export const ActivityBodyEffect = ({ activityId }: { activityId: string }) => {
89
const [activityFromStore] = useRecoilState(
@@ -16,7 +17,7 @@ export const ActivityBodyEffect = ({ activityId }: { activityId: string }) => {
1617
useEffect(() => {
1718
if (
1819
activityBody === '' &&
19-
activityFromStore &&
20+
isNonNullable(activityFromStore) &&
2021
activityBody !== activityFromStore.body
2122
) {
2223
setActivityBody(activityFromStore.body);

packages/twenty-front/src/modules/activities/components/ActivityEditorEffect.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Activity } from '@/activities/types/Activity';
1111
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
1212
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
1313
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
14+
import { isNonNullable } from '~/utils/isNonNullable';
1415

1516
export const ActivityEditorEffect = ({
1617
activityId,
@@ -57,7 +58,7 @@ export const ActivityEditorEffect = ({
5758
return;
5859
}
5960

60-
if (isActivityInCreateMode && activity) {
61+
if (isActivityInCreateMode && isNonNullable(activity)) {
6162
if (canCreateActivity) {
6263
upsertActivity({
6364
activity,
@@ -71,7 +72,7 @@ export const ActivityEditorEffect = ({
7172
}
7273

7374
set(isActivityInCreateModeState, false);
74-
} else if (activity) {
75+
} else if (isNonNullable(activity)) {
7576
if (
7677
activity.title !== activityTitle ||
7778
activity.body !== activityBody

packages/twenty-front/src/modules/activities/components/ActivityEditorFields.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
1414
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
1515
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
16+
import { isNonNullable } from '~/utils/isNonNullable';
1617

1718
const StyledPropertyBox = styled(PropertyBox)`
1819
padding: 0;
@@ -35,7 +36,7 @@ export const ActivityEditorFields = ({
3536
const upsertActivityMutation = async ({
3637
variables,
3738
}: RecordUpdateHookParams) => {
38-
if (activityFromStore) {
39+
if (isNonNullable(activityFromStore)) {
3940
await upsertActivity({
4041
activity: activityFromStore as Activity,
4142
input: variables.updateOneRecordInput,

packages/twenty-front/src/modules/activities/components/ActivityTitleEffect.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useRecoilState } from 'recoil';
33

44
import { activityTitleFamilyState } from '@/activities/states/activityTitleFamilyState';
55
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
6+
import { isNonNullable } from '~/utils/isNonNullable';
67

78
export const ActivityTitleEffect = ({ activityId }: { activityId: string }) => {
89
const [activityFromStore] = useRecoilState(
@@ -16,7 +17,7 @@ export const ActivityTitleEffect = ({ activityId }: { activityId: string }) => {
1617
useEffect(() => {
1718
if (
1819
activityTitle === '' &&
19-
activityFromStore &&
20+
isNonNullable(activityFromStore) &&
2021
activityTitle !== activityFromStore.title
2122
) {
2223
setActivityTitle(activityFromStore.title);

packages/twenty-front/src/modules/activities/emails/components/EmailThreads.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
TimelineThread,
3434
TimelineThreadsWithTotal,
3535
} from '~/generated/graphql';
36+
import { isNonNullable } from '~/utils/isNonNullable';
3637

3738
const StyledContainer = styled.div`
3839
display: flex;
@@ -140,7 +141,7 @@ export const EmailThreads = ({
140141
}
141142
};
142143

143-
if (error) {
144+
if (isNonNullable(error)) {
144145
enqueueSnackBar(error.message || 'Error loading email threads', {
145146
variant: 'error',
146147
});

packages/twenty-front/src/modules/activities/emails/utils/getDisplayNameFromParticipant.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { isNonEmptyString } from '@sniptt/guards';
2+
13
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
4+
import { isNonNullable } from '~/utils/isNonNullable';
25

36
export const getDisplayNameFromParticipant = ({
47
participant,
@@ -7,14 +10,14 @@ export const getDisplayNameFromParticipant = ({
710
participant: EmailThreadMessageParticipant;
811
shouldUseFullName?: boolean;
912
}) => {
10-
if (participant.person) {
13+
if (isNonNullable(participant.person)) {
1114
return (
1215
`${participant.person?.name?.firstName}` +
1316
(shouldUseFullName ? ` ${participant.person?.name?.lastName}` : '')
1417
);
1518
}
1619

17-
if (participant.workspaceMember) {
20+
if (isNonNullable(participant.workspaceMember)) {
1821
return (
1922
participant.workspaceMember?.name?.firstName +
2023
(shouldUseFullName
@@ -23,11 +26,11 @@ export const getDisplayNameFromParticipant = ({
2326
);
2427
}
2528

26-
if (participant.displayName) {
29+
if (isNonEmptyString(participant.displayName)) {
2730
return participant.displayName;
2831
}
2932

30-
if (participant.handle) {
33+
if (isNonEmptyString(participant.handle)) {
3134
return participant.handle;
3235
}
3336

packages/twenty-front/src/modules/activities/files/components/Attachments.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
AnimatedPlaceholderEmptyTextContainer,
1717
AnimatedPlaceholderEmptyTitle,
1818
} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
19+
import { isNonNullable } from '~/utils/isNonNullable';
1920

2021
const StyledAttachmentsContainer = styled.div`
2122
display: flex;
@@ -46,7 +47,7 @@ export const Attachments = ({
4647
const [isDraggingFile, setIsDraggingFile] = useState(false);
4748

4849
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
49-
if (e.target.files) onUploadFile?.(e.target.files[0]);
50+
if (isNonNullable(e.target.files)) onUploadFile?.(e.target.files[0]);
5051
};
5152

5253
const handleUploadFileClick = () => {

packages/twenty-front/src/modules/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export const useOpenCreateActivityDrawerForSelectedRowIds = (
4949
})
5050
.filter(isNonNullable);
5151

52-
if (relatedEntities) {
52+
if (isNonNullable(relatedEntities)) {
5353
activityTargetableObjectArray =
5454
activityTargetableObjectArray.concat(relatedEntities);
5555
}

packages/twenty-front/src/modules/activities/hooks/useUpsertActivity.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@ export const useUpsertActivity = () => {
112112
}
113113

114114
// Call optimistic effects
115-
if (weAreOnObjectShowPage && objectShowPageTargetableObject) {
115+
if (
116+
weAreOnObjectShowPage &&
117+
isNonNullable(objectShowPageTargetableObject)
118+
) {
116119
injectIntoTimelineActivitiesQueries({
117120
timelineTargetableObject: objectShowPageTargetableObject,
118121
activityToInject: activityWithConnection,

0 commit comments

Comments
 (0)