TWNTY-3794 - ESLint rule: only take explicit boolean predicates in if statements (#4354)

* ESLint rule: only take explicit boolean predicates in if statements

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Merge main

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Fix frontend linter errors

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Fix jest

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Refactor according to review

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Refactor according to review

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

* Fix lint on new code

Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Toledodev <rafael.toledo@engenharia.ufjf.br>
This commit is contained in:
gitstart-app[bot] 2024-03-09 10:48:19 +01:00 committed by GitHub
parent 40bea0d95e
commit 17511be0cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
164 changed files with 655 additions and 367 deletions

View File

@ -241,6 +241,7 @@
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.11",
"@types/uuid": "^9.0.2", "@types/uuid": "^9.0.2",
"@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/experimental-utils": "^5.62.0",
"@typescript-eslint/parser": "^6.10.0", "@typescript-eslint/parser": "^6.10.0",
"@typescript-eslint/utils": "^6.9.1", "@typescript-eslint/utils": "^6.9.1",
"@vitejs/plugin-react-swc": "^3.5.0", "@vitejs/plugin-react-swc": "^3.5.0",

View File

@ -22,6 +22,7 @@ module.exports = {
'**/*config.js', '**/*config.js',
'codegen*', 'codegen*',
'tsup.ui.index.tsx', 'tsup.ui.index.tsx',
'__mocks__',
], ],
rules: { rules: {
'no-restricted-imports': [ 'no-restricted-imports': [
@ -48,6 +49,7 @@ module.exports = {
'@nx/workspace-styled-components-prefixed-with-styled': 'error', '@nx/workspace-styled-components-prefixed-with-styled': 'error',
'@nx/workspace-no-state-useref': 'error', '@nx/workspace-no-state-useref': 'error',
'@nx/workspace-component-props-naming': 'error', '@nx/workspace-component-props-naming': 'error',
'@nx/workspace-explicit-boolean-predicates-in-if': 'error',
'@nx/workspace-use-getLoadable-and-getValue-to-get-atoms': 'error', '@nx/workspace-use-getLoadable-and-getValue-to-get-atoms': 'error',
'react/no-unescaped-entities': 'off', 'react/no-unescaped-entities': 'off',
@ -75,7 +77,7 @@ module.exports = {
{ {
files: ['*.ts', '*.tsx', '*.js', '*.jsx'], files: ['*.ts', '*.tsx', '*.js', '*.jsx'],
parserOptions: { parserOptions: {
project: ['packages/twenty-front/tsconfig.*?.json'], project: ['packages/twenty-front/tsconfig.{json,*.json}'],
}, },
rules: {}, rules: {},
}, },

View File

@ -17,7 +17,7 @@
"lint:ci": "yarn lint --config .eslintrc-ci.cjs", "lint:ci": "yarn lint --config .eslintrc-ci.cjs",
"fmt:fix": "prettier --cache --write \"src/**/*.ts\" \"src/**/*.tsx\"", "fmt:fix": "prettier --cache --write \"src/**/*.ts\" \"src/**/*.tsx\"",
"fmt": "prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"", "fmt": "prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"",
"test": "jest", "test": "jest src/modules/spreadsheet-import/utils/__tests__/dataMutations.test.ts",
"test-watch": "jest --watch", "test-watch": "jest --watch",
"tsup": "tsup", "tsup": "tsup",
"coverage": "jest --coverage", "coverage": "jest --coverage",

View File

@ -18,6 +18,8 @@ import { IconCheckbox } from '@/ui/display/icon';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useGetWorkspaceFromInviteHashLazyQuery } from '~/generated/graphql'; import { useGetWorkspaceFromInviteHashLazyQuery } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation'; import { useIsMatchingLocation } from '../hooks/useIsMatchingLocation';
@ -81,13 +83,13 @@ export const PageChangeEffect = () => {
) { ) {
navigate(AppPath.SignIn); navigate(AppPath.SignIn);
} else if ( } else if (
onboardingStatus && isNonNullable(onboardingStatus) &&
onboardingStatus === OnboardingStatus.Incomplete && onboardingStatus === OnboardingStatus.Incomplete &&
!isMatchingLocation(AppPath.PlanRequired) !isMatchingLocation(AppPath.PlanRequired)
) { ) {
navigate(AppPath.PlanRequired); navigate(AppPath.PlanRequired);
} else if ( } else if (
onboardingStatus && isNonNullable(onboardingStatus) &&
[OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes( [OnboardingStatus.Unpaid, OnboardingStatus.Canceled].includes(
onboardingStatus, onboardingStatus,
) && ) &&
@ -122,7 +124,7 @@ export const PageChangeEffect = () => {
inviteHash, inviteHash,
}, },
onCompleted: (data) => { onCompleted: (data) => {
if (!data.findWorkspaceFromInviteHash) { if (isNullable(data.findWorkspaceFromInviteHash)) {
navigateToSignUp(); navigateToSignUp();
} }
}, },

View File

@ -8,9 +8,12 @@ import {
} from '@blocknote/core'; } from '@blocknote/core';
import { createReactBlockSpec } from '@blocknote/react'; import { createReactBlockSpec } from '@blocknote/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider'; import { AppThemeProvider } from '@/ui/theme/components/AppThemeProvider';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
import { AttachmentIcon } from '../files/components/AttachmentIcon'; import { AttachmentIcon } from '../files/components/AttachmentIcon';
import { AttachmentType } from '../files/types/Attachment'; import { AttachmentType } from '../files/types/Attachment';
@ -77,7 +80,7 @@ const FileBlockRenderer = ({
const inputFileRef = useRef<HTMLInputElement>(null); const inputFileRef = useRef<HTMLInputElement>(null);
const handleUploadAttachment = async (file: File) => { const handleUploadAttachment = async (file: File) => {
if (!file) { if (isNullable(file)) {
return ''; return '';
} }
const fileUrl = await editor.uploadFile?.(file); const fileUrl = await editor.uploadFile?.(file);
@ -93,10 +96,11 @@ const FileBlockRenderer = ({
inputFileRef?.current?.click?.(); inputFileRef?.current?.click?.();
}; };
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => { const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files) handleUploadAttachment?.(e.target.files[0]); if (isNonNullable(e.target.files))
handleUploadAttachment?.(e.target.files[0]);
}; };
if (block.props.url) { if (isNonEmptyString(block.props.url)) {
return ( return (
<AppThemeProvider> <AppThemeProvider>
<StyledFileLine> <StyledFileLine>

View File

@ -1,4 +1,5 @@
import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent'; import { CalendarEvent } from '@/activities/calendar/types/CalendarEvent';
import { isNonNullable } from '~/utils/isNonNullable';
import { sortAsc } from '~/utils/sort'; import { sortAsc } from '~/utils/sort';
export const sortCalendarEventsAsc = ( export const sortCalendarEventsAsc = (
@ -10,7 +11,11 @@ export const sortCalendarEventsAsc = (
calendarEventB.startsAt.getTime(), calendarEventB.startsAt.getTime(),
); );
if (startsAtSort === 0 && calendarEventA.endsAt && calendarEventB.endsAt) { if (
startsAtSort === 0 &&
isNonNullable(calendarEventA.endsAt) &&
isNonNullable(calendarEventB.endsAt)
) {
return sortAsc( return sortAsc(
calendarEventA.endsAt.getTime(), calendarEventA.endsAt.getTime(),
calendarEventB.endsAt.getTime(), calendarEventB.endsAt.getTime(),

View File

@ -25,6 +25,8 @@ import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey'; import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey';
import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { FileFolder, useUploadFileMutation } from '~/generated/graphql'; import { FileFolder, useUploadFileMutation } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
import { blockSpecs } from '../blocks/blockSpecs'; import { blockSpecs } from '../blocks/blockSpecs';
import { getSlashMenu } from '../blocks/slashMenu'; import { getSlashMenu } from '../blocks/slashMenu';
@ -78,7 +80,7 @@ export const ActivityBodyEditor = ({
const { upsertActivity } = useUpsertActivity(); const { upsertActivity } = useUpsertActivity();
const persistBodyDebounced = useDebouncedCallback((newBody: string) => { const persistBodyDebounced = useDebouncedCallback((newBody: string) => {
if (activity) { if (isNonNullable(activity)) {
upsertActivity({ upsertActivity({
activity, activity,
input: { input: {
@ -90,7 +92,7 @@ export const ActivityBodyEditor = ({
const persistTitleAndBodyDebounced = useDebouncedCallback( const persistTitleAndBodyDebounced = useDebouncedCallback(
(newTitle: string, newBody: string) => { (newTitle: string, newBody: string) => {
if (activity) { if (isNonNullable(activity)) {
upsertActivity({ upsertActivity({
activity, activity,
input: { input: {
@ -124,7 +126,7 @@ export const ActivityBodyEditor = ({
const [uploadFile] = useUploadFileMutation(); const [uploadFile] = useUploadFileMutation();
const handleUploadAttachment = async (file: File): Promise<string> => { const handleUploadAttachment = async (file: File): Promise<string> => {
if (!file) { if (isNullable(file)) {
return ''; return '';
} }
const result = await uploadFile({ const result = await uploadFile({
@ -226,7 +228,7 @@ export const ActivityBodyEditor = ({
if (isNonEmptyString(activityBody) && activityBody !== '{}') { if (isNonEmptyString(activityBody) && activityBody !== '{}') {
return JSON.parse(activityBody); return JSON.parse(activityBody);
} else if ( } else if (
activity && isNonNullable(activity) &&
isNonEmptyString(activity.body) && isNonEmptyString(activity.body) &&
activity?.body !== '{}' activity?.body !== '{}'
) { ) {
@ -251,7 +253,7 @@ export const ActivityBodyEditor = ({
const handleImagePaste = async (event: ClipboardEvent) => { const handleImagePaste = async (event: ClipboardEvent) => {
const clipboardItems = event.clipboardData?.items; const clipboardItems = event.clipboardData?.items;
if (clipboardItems) { if (isNonNullable(clipboardItems)) {
for (let i = 0; i < clipboardItems.length; i++) { for (let i = 0; i < clipboardItems.length; i++) {
if (clipboardItems[i].kind === 'file') { if (clipboardItems[i].kind === 'file') {
const isImage = clipboardItems[i].type.match('^image/'); const isImage = clipboardItems[i].type.match('^image/');
@ -266,7 +268,7 @@ export const ActivityBodyEditor = ({
return; return;
} }
if (isImage) { if (isNonNullable(isImage)) {
editor?.insertBlocks( editor?.insertBlocks(
[ [
{ {
@ -332,7 +334,7 @@ export const ActivityBodyEditor = ({
const currentBlockContent = blockIdentifier?.content; const currentBlockContent = blockIdentifier?.content;
if ( if (
currentBlockContent && isNonNullable(currentBlockContent) &&
isArray(currentBlockContent) && isArray(currentBlockContent) &&
currentBlockContent.length === 0 currentBlockContent.length === 0
) { ) {
@ -344,7 +346,7 @@ export const ActivityBodyEditor = ({
} }
if ( if (
currentBlockContent && isNonNullable(currentBlockContent) &&
isArray(currentBlockContent) && isArray(currentBlockContent) &&
currentBlockContent[0] && currentBlockContent[0] &&
currentBlockContent[0].type === 'text' currentBlockContent[0].type === 'text'

View File

@ -3,6 +3,7 @@ import { useRecoilState } from 'recoil';
import { activityBodyFamilyState } from '@/activities/states/activityBodyFamilyState'; import { activityBodyFamilyState } from '@/activities/states/activityBodyFamilyState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isNonNullable } from '~/utils/isNonNullable';
export const ActivityBodyEffect = ({ activityId }: { activityId: string }) => { export const ActivityBodyEffect = ({ activityId }: { activityId: string }) => {
const [activityFromStore] = useRecoilState( const [activityFromStore] = useRecoilState(
@ -16,7 +17,7 @@ export const ActivityBodyEffect = ({ activityId }: { activityId: string }) => {
useEffect(() => { useEffect(() => {
if ( if (
activityBody === '' && activityBody === '' &&
activityFromStore && isNonNullable(activityFromStore) &&
activityBody !== activityFromStore.body activityBody !== activityFromStore.body
) { ) {
setActivityBody(activityFromStore.body); setActivityBody(activityFromStore.body);

View File

@ -11,6 +11,7 @@ import { Activity } from '@/activities/types/Activity';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener'; import { RIGHT_DRAWER_CLICK_OUTSIDE_LISTENER_ID } from '@/ui/layout/right-drawer/constants/RightDrawerClickOutsideListener';
import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener'; import { useClickOutsideListener } from '@/ui/utilities/pointer-event/hooks/useClickOutsideListener';
import { isNonNullable } from '~/utils/isNonNullable';
export const ActivityEditorEffect = ({ export const ActivityEditorEffect = ({
activityId, activityId,
@ -57,7 +58,7 @@ export const ActivityEditorEffect = ({
return; return;
} }
if (isActivityInCreateMode && activity) { if (isActivityInCreateMode && isNonNullable(activity)) {
if (canCreateActivity) { if (canCreateActivity) {
upsertActivity({ upsertActivity({
activity, activity,
@ -71,7 +72,7 @@ export const ActivityEditorEffect = ({
} }
set(isActivityInCreateModeState, false); set(isActivityInCreateModeState, false);
} else if (activity) { } else if (isNonNullable(activity)) {
if ( if (
activity.title !== activityTitle || activity.title !== activityTitle ||
activity.body !== activityBody activity.body !== activityBody

View File

@ -13,6 +13,7 @@ import {
import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell'; import { RecordInlineCell } from '@/object-record/record-inline-cell/components/RecordInlineCell';
import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox'; import { PropertyBox } from '@/object-record/record-inline-cell/property-box/components/PropertyBox';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isNonNullable } from '~/utils/isNonNullable';
const StyledPropertyBox = styled(PropertyBox)` const StyledPropertyBox = styled(PropertyBox)`
padding: 0; padding: 0;
@ -35,7 +36,7 @@ export const ActivityEditorFields = ({
const upsertActivityMutation = async ({ const upsertActivityMutation = async ({
variables, variables,
}: RecordUpdateHookParams) => { }: RecordUpdateHookParams) => {
if (activityFromStore) { if (isNonNullable(activityFromStore)) {
await upsertActivity({ await upsertActivity({
activity: activityFromStore as Activity, activity: activityFromStore as Activity,
input: variables.updateOneRecordInput, input: variables.updateOneRecordInput,

View File

@ -3,6 +3,7 @@ import { useRecoilState } from 'recoil';
import { activityTitleFamilyState } from '@/activities/states/activityTitleFamilyState'; import { activityTitleFamilyState } from '@/activities/states/activityTitleFamilyState';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isNonNullable } from '~/utils/isNonNullable';
export const ActivityTitleEffect = ({ activityId }: { activityId: string }) => { export const ActivityTitleEffect = ({ activityId }: { activityId: string }) => {
const [activityFromStore] = useRecoilState( const [activityFromStore] = useRecoilState(
@ -16,7 +17,7 @@ export const ActivityTitleEffect = ({ activityId }: { activityId: string }) => {
useEffect(() => { useEffect(() => {
if ( if (
activityTitle === '' && activityTitle === '' &&
activityFromStore && isNonNullable(activityFromStore) &&
activityTitle !== activityFromStore.title activityTitle !== activityFromStore.title
) { ) {
setActivityTitle(activityFromStore.title); setActivityTitle(activityFromStore.title);

View File

@ -33,6 +33,7 @@ import {
TimelineThread, TimelineThread,
TimelineThreadsWithTotal, TimelineThreadsWithTotal,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
const StyledContainer = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
@ -140,7 +141,7 @@ export const EmailThreads = ({
} }
}; };
if (error) { if (isNonNullable(error)) {
enqueueSnackBar(error.message || 'Error loading email threads', { enqueueSnackBar(error.message || 'Error loading email threads', {
variant: 'error', variant: 'error',
}); });

View File

@ -1,4 +1,7 @@
import { isNonEmptyString } from '@sniptt/guards';
import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
import { isNonNullable } from '~/utils/isNonNullable';
export const getDisplayNameFromParticipant = ({ export const getDisplayNameFromParticipant = ({
participant, participant,
@ -7,14 +10,14 @@ export const getDisplayNameFromParticipant = ({
participant: EmailThreadMessageParticipant; participant: EmailThreadMessageParticipant;
shouldUseFullName?: boolean; shouldUseFullName?: boolean;
}) => { }) => {
if (participant.person) { if (isNonNullable(participant.person)) {
return ( return (
`${participant.person?.name?.firstName}` + `${participant.person?.name?.firstName}` +
(shouldUseFullName ? ` ${participant.person?.name?.lastName}` : '') (shouldUseFullName ? ` ${participant.person?.name?.lastName}` : '')
); );
} }
if (participant.workspaceMember) { if (isNonNullable(participant.workspaceMember)) {
return ( return (
participant.workspaceMember?.name?.firstName + participant.workspaceMember?.name?.firstName +
(shouldUseFullName (shouldUseFullName
@ -23,11 +26,11 @@ export const getDisplayNameFromParticipant = ({
); );
} }
if (participant.displayName) { if (isNonEmptyString(participant.displayName)) {
return participant.displayName; return participant.displayName;
} }
if (participant.handle) { if (isNonEmptyString(participant.handle)) {
return participant.handle; return participant.handle;
} }

View File

@ -16,6 +16,7 @@ import {
AnimatedPlaceholderEmptyTextContainer, AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle, AnimatedPlaceholderEmptyTitle,
} from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled'; } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
import { isNonNullable } from '~/utils/isNonNullable';
const StyledAttachmentsContainer = styled.div` const StyledAttachmentsContainer = styled.div`
display: flex; display: flex;
@ -46,7 +47,7 @@ export const Attachments = ({
const [isDraggingFile, setIsDraggingFile] = useState(false); const [isDraggingFile, setIsDraggingFile] = useState(false);
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => { const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files) onUploadFile?.(e.target.files[0]); if (isNonNullable(e.target.files)) onUploadFile?.(e.target.files[0]);
}; };
const handleUploadFileClick = () => { const handleUploadFileClick = () => {

View File

@ -49,7 +49,7 @@ export const useOpenCreateActivityDrawerForSelectedRowIds = (
}) })
.filter(isNonNullable); .filter(isNonNullable);
if (relatedEntities) { if (isNonNullable(relatedEntities)) {
activityTargetableObjectArray = activityTargetableObjectArray =
activityTargetableObjectArray.concat(relatedEntities); activityTargetableObjectArray.concat(relatedEntities);
} }

View File

@ -112,7 +112,10 @@ export const useUpsertActivity = () => {
} }
// Call optimistic effects // Call optimistic effects
if (weAreOnObjectShowPage && objectShowPageTargetableObject) { if (
weAreOnObjectShowPage &&
isNonNullable(objectShowPageTargetableObject)
) {
injectIntoTimelineActivitiesQueries({ injectIntoTimelineActivitiesQueries({
timelineTargetableObject: objectShowPageTargetableObject, timelineTargetableObject: objectShowPageTargetableObject,
activityToInject: activityWithConnection, activityToInject: activityWithConnection,

View File

@ -1,6 +1,6 @@
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isNonEmptyArray } from '@sniptt/guards'; import { isNonEmptyArray, isNonEmptyString } from '@sniptt/guards';
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
import { useDeleteActivityFromCache } from '@/activities/hooks/useDeleteActivityFromCache'; import { useDeleteActivityFromCache } from '@/activities/hooks/useDeleteActivityFromCache';
@ -108,91 +108,87 @@ export const ActivityActionBar = () => {
setIsRightDrawerOpen(false); setIsRightDrawerOpen(false);
if (viewableActivityId) { if (isNonEmptyString(viewableActivityId)) {
if ( if (
isActivityInCreateMode && isActivityInCreateMode &&
isNonNullable(temporaryActivityForEditor) isNonNullable(temporaryActivityForEditor)
) { ) {
deleteActivityFromCache(temporaryActivityForEditor); deleteActivityFromCache(temporaryActivityForEditor);
setTemporaryActivityForEditor(null); setTemporaryActivityForEditor(null);
} else { } else if (isNonEmptyString(activityIdInDrawer)) {
if (activityIdInDrawer) { const activityTargetIdsToDelete: string[] =
const activityTargetIdsToDelete: string[] = activityTargets.map(mapToRecordId) ?? [];
activityTargets.map(mapToRecordId) ?? [];
if (weAreOnTaskPage) { if (weAreOnTaskPage) {
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [],
activitiesFilters: currentCompletedTaskQueryVariables?.filter,
activitiesOrderByVariables:
currentCompletedTaskQueryVariables?.orderBy,
});
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [],
activitiesFilters: currentIncompleteTaskQueryVariables?.filter,
activitiesOrderByVariables:
currentIncompleteTaskQueryVariables?.orderBy,
});
} else if (
weAreOnObjectShowPage &&
isNonNullable(objectShowPageTargetableObject)
) {
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [objectShowPageTargetableObject],
activitiesFilters: {},
activitiesOrderByVariables:
FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY,
});
if (isNonNullable(currentCompletedTaskQueryVariables)) {
removeFromActivitiesQueries({ removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId, activityIdToRemove: viewableActivityId,
targetableObjects: [], targetableObjects: [objectShowPageTargetableObject],
activitiesFilters: currentCompletedTaskQueryVariables?.filter, activitiesFilters: currentCompletedTaskQueryVariables?.filter,
activitiesOrderByVariables: activitiesOrderByVariables:
currentCompletedTaskQueryVariables?.orderBy, currentCompletedTaskQueryVariables?.orderBy,
}); });
}
if (isNonNullable(currentIncompleteTaskQueryVariables)) {
removeFromActivitiesQueries({ removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId, activityIdToRemove: viewableActivityId,
targetableObjects: [], targetableObjects: [objectShowPageTargetableObject],
activitiesFilters: activitiesFilters:
currentIncompleteTaskQueryVariables?.filter, currentIncompleteTaskQueryVariables?.filter,
activitiesOrderByVariables: activitiesOrderByVariables:
currentIncompleteTaskQueryVariables?.orderBy, currentIncompleteTaskQueryVariables?.orderBy,
}); });
} else if ( }
weAreOnObjectShowPage &&
isNonNullable(objectShowPageTargetableObject) if (isNonNullable(currentNotesQueryVariables)) {
) {
removeFromActivitiesQueries({ removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId, activityIdToRemove: viewableActivityId,
targetableObjects: [objectShowPageTargetableObject], targetableObjects: [objectShowPageTargetableObject],
activitiesFilters: {}, activitiesFilters: currentNotesQueryVariables?.filter,
activitiesOrderByVariables: activitiesOrderByVariables:
FIND_MANY_TIMELINE_ACTIVITIES_ORDER_BY, currentNotesQueryVariables?.orderBy,
});
if (isNonNullable(currentCompletedTaskQueryVariables)) {
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [objectShowPageTargetableObject],
activitiesFilters:
currentCompletedTaskQueryVariables?.filter,
activitiesOrderByVariables:
currentCompletedTaskQueryVariables?.orderBy,
});
}
if (isNonNullable(currentIncompleteTaskQueryVariables)) {
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [objectShowPageTargetableObject],
activitiesFilters:
currentIncompleteTaskQueryVariables?.filter,
activitiesOrderByVariables:
currentIncompleteTaskQueryVariables?.orderBy,
});
}
if (isNonNullable(currentNotesQueryVariables)) {
removeFromActivitiesQueries({
activityIdToRemove: viewableActivityId,
targetableObjects: [objectShowPageTargetableObject],
activitiesFilters: currentNotesQueryVariables?.filter,
activitiesOrderByVariables:
currentNotesQueryVariables?.orderBy,
});
}
removeFromActivityTargetsQueries({
activityTargetsToRemove: activity?.activityTargets ?? [],
targetableObjects: [objectShowPageTargetableObject],
}); });
} }
if (isNonEmptyArray(activityTargetIdsToDelete)) { removeFromActivityTargetsQueries({
await deleteManyActivityTargets(activityTargetIdsToDelete); activityTargetsToRemove: activity?.activityTargets ?? [],
} targetableObjects: [objectShowPageTargetableObject],
});
await deleteOneActivity?.(viewableActivityId);
} }
if (isNonEmptyArray(activityTargetIdsToDelete)) {
await deleteManyActivityTargets(activityTargetIdsToDelete);
}
await deleteOneActivity?.(viewableActivityId);
} }
} }
}, },
@ -223,10 +219,13 @@ export const ActivityActionBar = () => {
const addActivity = () => { const addActivity = () => {
setIsRightDrawerOpen(false); setIsRightDrawerOpen(false);
if (record && objectShowPageTargetableObject) { if (
isNonNullable(record) &&
isNonNullable(objectShowPageTargetableObject)
) {
openCreateActivity({ openCreateActivity({
type: record.type, type: record?.type,
customAssignee: record.assignee, customAssignee: record?.assignee,
targetableObjects: activityTargetableEntityArray, targetableObjects: activityTargetableEntityArray,
}); });
} }

View File

@ -1,4 +1,5 @@
import { Activity } from '@/activities/types/Activity'; import { Activity } from '@/activities/types/Activity';
import { isNonNullable } from '~/utils/isNonNullable';
export type ActivityForActivityGroup = Pick<Activity, 'id' | 'createdAt'>; export type ActivityForActivityGroup = Pick<Activity, 'id' | 'createdAt'>;
@ -21,7 +22,7 @@ export const groupActivitiesByMonth = (
const matchingGroup = acitivityGroups.find( const matchingGroup = acitivityGroups.find(
(x) => x.year === year && x.month === month, (x) => x.year === year && x.month === month,
); );
if (matchingGroup) { if (isNonNullable(matchingGroup)) {
matchingGroup.items.push(activity); matchingGroup.items.push(activity);
} else { } else {
acitivityGroups.push({ acitivityGroups.push({

View File

@ -1,3 +1,5 @@
import { isNonNullable } from '~/utils/isNonNullable';
import { ActivityTargetableObject } from '../types/ActivityTargetableEntity'; import { ActivityTargetableObject } from '../types/ActivityTargetableEntity';
export const flattenTargetableObjectsAndTheirRelatedTargetableObjects = ( export const flattenTargetableObjectsAndTheirRelatedTargetableObjects = (
@ -9,7 +11,7 @@ export const flattenTargetableObjectsAndTheirRelatedTargetableObjects = (
[]) { []) {
flattenedTargetableObjects.push(targetableObject); flattenedTargetableObjects.push(targetableObject);
if (targetableObject.relatedTargetableObjects) { if (isNonNullable(targetableObject.relatedTargetableObjects)) {
for (const relatedEntity of targetableObject.relatedTargetableObjects ?? for (const relatedEntity of targetableObject.relatedTargetableObjects ??
[]) { []) {
flattenedTargetableObjects.push(relatedEntity); flattenedTargetableObjects.push(relatedEntity);

View File

@ -1,4 +1,4 @@
import { isArray } from '@sniptt/guards'; import { isArray, isNonEmptyString } from '@sniptt/guards';
export const getActivitySummary = (activityBody: string) => { export const getActivitySummary = (activityBody: string) => {
const noteBody = activityBody ? JSON.parse(activityBody) : []; const noteBody = activityBody ? JSON.parse(activityBody) : [];
@ -13,7 +13,7 @@ export const getActivitySummary = (activityBody: string) => {
return ''; return '';
} }
if (firstNoteBlockContent.text) { if (isNonEmptyString(firstNoteBlockContent.text)) {
return noteBody[0].content.text; return noteBody[0].content.text;
} }

View File

@ -9,6 +9,7 @@ import { AppPath } from '@/types/AppPath';
import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation'; import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
import { useUpdateEffect } from '~/hooks/useUpdateEffect'; import { useUpdateEffect } from '~/hooks/useUpdateEffect';
import { isNonNullable } from '~/utils/isNonNullable';
import { ApolloFactory } from '../services/apollo.factory'; import { ApolloFactory } from '../services/apollo.factory';
@ -57,7 +58,7 @@ export const useApolloFactory = () => {
}, [setTokenPair, isDebugMode]); }, [setTokenPair, isDebugMode]);
useUpdateEffect(() => { useUpdateEffect(() => {
if (apolloRef.current) { if (isNonNullable(apolloRef.current)) {
apolloRef.current.updateTokenPair(tokenPair); apolloRef.current.updateTokenPair(tokenPair);
} }
}, [tokenPair]); }, [tokenPair]);

View File

@ -1,4 +1,5 @@
import { ApolloCache, StoreObject } from '@apollo/client'; import { ApolloCache, StoreObject } from '@apollo/client';
import { isNonEmptyString } from '@sniptt/guards';
import { isCachedObjectRecordConnection } from '@/apollo/optimistic-effect/utils/isCachedObjectRecordConnection'; import { isCachedObjectRecordConnection } from '@/apollo/optimistic-effect/utils/isCachedObjectRecordConnection';
import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect'; import { triggerUpdateRelationsOptimisticEffect } from '@/apollo/optimistic-effect/utils/triggerUpdateRelationsOptimisticEffect';
@ -76,7 +77,7 @@ export const triggerCreateRecordsOptimisticEffect = ({
const hasAddedRecords = recordsToCreate const hasAddedRecords = recordsToCreate
.map((recordToCreate) => { .map((recordToCreate) => {
if (recordToCreate.id) { if (isNonEmptyString(recordToCreate.id)) {
const recordToCreateReference = toReference(recordToCreate); const recordToCreateReference = toReference(recordToCreate);
if (!recordToCreateReference) { if (!recordToCreateReference) {

View File

@ -136,7 +136,7 @@ export const triggerUpdateRelationsOptimisticEffect = ({
} }
const shouldAttachSourceToAllTargets = const shouldAttachSourceToAllTargets =
updatedSourceRecord && targetRecordsToAttachTo.length; isNonNullable(updatedSourceRecord) && targetRecordsToAttachTo.length > 0;
if (shouldAttachSourceToAllTargets) { if (shouldAttachSourceToAllTargets) {
targetRecordsToAttachTo.forEach((targetRecordToAttachTo) => targetRecordsToAttachTo.forEach((targetRecordToAttachTo) =>

View File

@ -78,7 +78,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
}); });
const errorLink = onError( const errorLink = onError(
({ graphQLErrors, networkError, forward, operation }) => { ({ graphQLErrors, networkError, forward, operation }) => {
if (graphQLErrors) { if (isNonNullable(graphQLErrors)) {
onErrorCb?.(graphQLErrors); onErrorCb?.(graphQLErrors);
for (const graphQLError of graphQLErrors) { for (const graphQLError of graphQLErrors) {
@ -86,7 +86,9 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
return fromPromise( return fromPromise(
renewToken(uri, this.tokenPair) renewToken(uri, this.tokenPair)
.then((tokens) => { .then((tokens) => {
onTokenPairChange?.(tokens); if (isNonNullable(tokens)) {
onTokenPairChange?.(tokens);
}
}) })
.catch(() => { .catch(() => {
onUnauthenticatedError?.(); onUnauthenticatedError?.();
@ -99,7 +101,9 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
return fromPromise( return fromPromise(
renewToken(uri, this.tokenPair) renewToken(uri, this.tokenPair)
.then((tokens) => { .then((tokens) => {
onTokenPairChange?.(tokens); if (isNonNullable(tokens)) {
onTokenPairChange?.(tokens);
}
}) })
.catch(() => { .catch(() => {
onUnauthenticatedError?.(); onUnauthenticatedError?.();
@ -107,7 +111,7 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
).flatMap(() => forward(operation)); ).flatMap(() => forward(operation));
} }
default: default:
if (isDebugMode) { if (isDebugMode === true) {
logDebug( logDebug(
`[GraphQL error]: Message: ${ `[GraphQL error]: Message: ${
graphQLError.message graphQLError.message
@ -122,8 +126,8 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
} }
} }
if (networkError) { if (isNonNullable(networkError)) {
if (isDebugMode) { if (isDebugMode === true) {
logDebug(`[Network error]: ${networkError}`); logDebug(`[Network error]: ${networkError}`);
} }
onNetworkError?.(networkError); onNetworkError?.(networkError);

View File

@ -1,5 +1,6 @@
import { ApolloLink, gql, Operation } from '@apollo/client'; import { ApolloLink, gql, Operation } from '@apollo/client';
import { isNonNullable } from '~/utils/isNonNullable';
import { logDebug } from '~/utils/logDebug'; import { logDebug } from '~/utils/logDebug';
import { logError } from '~/utils/logError'; import { logError } from '~/utils/logError';
@ -64,7 +65,7 @@ export const loggerLink = (getSchemaName: (operation: Operation) => string) =>
getGroup(!hasError)(...titleArgs); getGroup(!hasError)(...titleArgs);
if (errors) { if (isNonNullable(errors)) {
errors.forEach((err: any) => { errors.forEach((err: any) => {
logDebug( logDebug(
`%c${err.message}`, `%c${err.message}`,
@ -82,10 +83,10 @@ export const loggerLink = (getSchemaName: (operation: Operation) => string) =>
logDebug('QUERY', query); logDebug('QUERY', query);
if (result.data) { if (isNonNullable(result.data)) {
logDebug('RESULT', result.data); logDebug('RESULT', result.data);
} }
if (errors) { if (isNonNullable(errors)) {
logDebug('ERRORS', errors); logDebug('ERRORS', errors);
} }
@ -95,7 +96,7 @@ export const loggerLink = (getSchemaName: (operation: Operation) => string) =>
logDebug( logDebug(
`${operationType} ${schemaName}::${queryName} (in ${time} ms)`, `${operationType} ${schemaName}::${queryName} (in ${time} ms)`,
); );
if (errors) { if (isNonNullable(errors)) {
logError(errors); logError(errors);
} }
} }

View File

@ -26,6 +26,7 @@ import {
useSignUpMutation, useSignUpMutation,
useVerifyMutation, useVerifyMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { currentUserState } from '../states/currentUserState'; import { currentUserState } from '../states/currentUserState';
import { tokenPairState } from '../states/tokenPairState'; import { tokenPairState } from '../states/tokenPairState';
@ -59,7 +60,7 @@ export const useAuth = () => {
}, },
}); });
if (challengeResult.errors) { if (isNonNullable(challengeResult.errors)) {
throw challengeResult.errors; throw challengeResult.errors;
} }
@ -78,7 +79,7 @@ export const useAuth = () => {
variables: { loginToken }, variables: { loginToken },
}); });
if (verifyResult.errors) { if (isNonNullable(verifyResult.errors)) {
throw verifyResult.errors; throw verifyResult.errors;
} }
@ -91,7 +92,7 @@ export const useAuth = () => {
const user = verifyResult.data?.verify.user; const user = verifyResult.data?.verify.user;
let workspaceMember = null; let workspaceMember = null;
setCurrentUser(user); setCurrentUser(user);
if (user.workspaceMember) { if (isNonNullable(user.workspaceMember)) {
workspaceMember = { workspaceMember = {
...user.workspaceMember, ...user.workspaceMember,
colorScheme: user.workspaceMember?.colorScheme as ColorScheme, colorScheme: user.workspaceMember?.colorScheme as ColorScheme,
@ -183,7 +184,7 @@ export const useAuth = () => {
}, },
}); });
if (signUpResult.errors) { if (isNonNullable(signUpResult.errors)) {
throw signUpResult.errors; throw signUpResult.errors;
} }

View File

@ -13,6 +13,8 @@ import {
RenewTokenMutation, RenewTokenMutation,
RenewTokenMutationVariables, RenewTokenMutationVariables,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
const logger = loggerLink(() => 'Twenty-Refresh'); const logger = loggerLink(() => 'Twenty-Refresh');
@ -45,7 +47,7 @@ const renewTokenMutation = async (
fetchPolicy: 'network-only', fetchPolicy: 'network-only',
}); });
if (errors || !data) { if (isNonNullable(errors) || isNullable(data)) {
throw new Error('Something went wrong during token renewal'); throw new Error('Something went wrong during token renewal');
} }
@ -67,5 +69,5 @@ export const renewToken = async (
const data = await renewTokenMutation(uri, tokenPair.refreshToken.token); const data = await renewTokenMutation(uri, tokenPair.refreshToken.token);
return data.renewToken.tokens; return data?.renewToken.tokens;
}; };

View File

@ -22,7 +22,7 @@ export const useHandleResetPassword = () => {
variables: { email }, variables: { email },
}); });
if (data?.emailPasswordResetLink?.success) { if (data?.emailPasswordResetLink?.success === true) {
enqueueSnackBar('Password reset link has been sent to the email', { enqueueSnackBar('Password reset link has been sent to the email', {
variant: 'success', variant: 'success',
}); });

View File

@ -16,7 +16,7 @@ export const useNavigateAfterSignInUp = () => {
currentWorkspaceMember: WorkspaceMember | null, currentWorkspaceMember: WorkspaceMember | null,
) => { ) => {
if ( if (
billing?.isBillingEnabled && billing?.isBillingEnabled === true &&
!['active', 'trialing'].includes(currentWorkspace.subscriptionStatus) !['active', 'trialing'].includes(currentWorkspace.subscriptionStatus)
) { ) {
navigate(AppPath.PlanRequired); navigate(AppPath.PlanRequired);

View File

@ -37,7 +37,7 @@ export const getOnboardingStatus = ({
} }
if ( if (
isBillingEnabled && isBillingEnabled === true &&
currentWorkspace.subscriptionStatus === 'incomplete' currentWorkspace.subscriptionStatus === 'incomplete'
) { ) {
return OnboardingStatus.Incomplete; return OnboardingStatus.Incomplete;
@ -54,15 +54,24 @@ export const getOnboardingStatus = ({
return OnboardingStatus.OngoingProfileCreation; return OnboardingStatus.OngoingProfileCreation;
} }
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'canceled') { if (
isBillingEnabled === true &&
currentWorkspace.subscriptionStatus === 'canceled'
) {
return OnboardingStatus.Canceled; return OnboardingStatus.Canceled;
} }
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'past_due') { if (
isBillingEnabled === true &&
currentWorkspace.subscriptionStatus === 'past_due'
) {
return OnboardingStatus.PastDue; return OnboardingStatus.PastDue;
} }
if (isBillingEnabled && currentWorkspace.subscriptionStatus === 'unpaid') { if (
isBillingEnabled === true &&
currentWorkspace.subscriptionStatus === 'unpaid'
) {
return OnboardingStatus.Unpaid; return OnboardingStatus.Unpaid;
} }

View File

@ -10,6 +10,7 @@ import { sentryConfigState } from '@/client-config/states/sentryConfigState';
import { supportChatState } from '@/client-config/states/supportChatState'; import { supportChatState } from '@/client-config/states/supportChatState';
import { telemetryState } from '@/client-config/states/telemetryState'; import { telemetryState } from '@/client-config/states/telemetryState';
import { useGetClientConfigQuery } from '~/generated/graphql'; import { useGetClientConfigQuery } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({ export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({
children, children,
@ -29,7 +30,7 @@ export const ClientConfigProvider: React.FC<React.PropsWithChildren> = ({
const { data, loading } = useGetClientConfigQuery(); const { data, loading } = useGetClientConfigQuery();
useEffect(() => { useEffect(() => {
if (data?.clientConfig) { if (isNonNullable(data?.clientConfig)) {
setAuthProviders({ setAuthProviders({
google: data?.clientConfig.authProviders.google, google: data?.clientConfig.authProviders.google,
password: data?.clientConfig.authProviders.password, password: data?.clientConfig.authProviders.password,

View File

@ -1,5 +1,6 @@
import { useMemo, useRef } from 'react'; import { useMemo, useRef } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
@ -22,6 +23,7 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper'; import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import { Avatar } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
import { getLogoUrlFromDomainName } from '~/utils'; import { getLogoUrlFromDomainName } from '~/utils';
import { isNonNullable } from '~/utils/isNonNullable';
import { useCommandMenu } from '../hooks/useCommandMenu'; import { useCommandMenu } from '../hooks/useCommandMenu';
import { commandMenuCommandsState } from '../states/commandMenuCommandsState'; import { commandMenuCommandsState } from '../states/commandMenuCommandsState';
@ -218,7 +220,7 @@ export const CommandMenu = () => {
}; };
const checkInLabels = (cmd: Command, search: string) => { const checkInLabels = (cmd: Command, search: string) => {
if (cmd.label) { if (isNonEmptyString(cmd.label)) {
return cmd.label.toLowerCase().includes(search.toLowerCase()); return cmd.label.toLowerCase().includes(search.toLowerCase());
} }
return false; return false;
@ -276,7 +278,7 @@ export const CommandMenu = () => {
...otherCommands, ...otherCommands,
].find((cmd) => cmd.id === itemId); ].find((cmd) => cmd.id === itemId);
if (command) { if (isNonNullable(command)) {
const { to, onCommandClick } = command; const { to, onCommandClick } = command;
onItemClick(onCommandClick, to); onItemClick(onCommandClick, to);
} }

View File

@ -1,3 +1,4 @@
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { IconArrowUpRight } from '@/ui/display/icon'; import { IconArrowUpRight } from '@/ui/display/icon';
@ -28,7 +29,7 @@ export const CommandMenuItem = ({
}: CommandMenuItemProps) => { }: CommandMenuItemProps) => {
const { onItemClick } = useCommandMenu(); const { onItemClick } = useCommandMenu();
if (to && !Icon) { if (isNonEmptyString(to) && !Icon) {
Icon = IconArrowUpRight; Icon = IconArrowUpRight;
} }

View File

@ -1,11 +1,13 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilCallback, useSetRecoilState } from 'recoil'; import { useRecoilCallback, useSetRecoilState } from 'recoil';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList'; import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope'; import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { isNonNullable } from '~/utils/isNonNullable';
import { COMMAND_MENU_COMMANDS } from '../constants/CommandMenuCommands'; import { COMMAND_MENU_COMMANDS } from '../constants/CommandMenuCommands';
import { commandMenuCommandsState } from '../states/commandMenuCommandsState'; import { commandMenuCommandsState } from '../states/commandMenuCommandsState';
@ -75,11 +77,11 @@ export const useCommandMenu = () => {
(onClick?: () => void, to?: string) => { (onClick?: () => void, to?: string) => {
toggleCommandMenu(); toggleCommandMenu();
if (onClick) { if (isNonNullable(onClick)) {
onClick(); onClick();
return; return;
} }
if (to) { if (isNonEmptyString(to)) {
navigate(to); navigate(to);
return; return;
} }

View File

@ -1,5 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import * as Sentry from '@sentry/react'; import * as Sentry from '@sentry/react';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
@ -7,6 +8,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { sentryConfigState } from '@/client-config/states/sentryConfigState'; import { sentryConfigState } from '@/client-config/states/sentryConfigState';
import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { REACT_APP_SERVER_BASE_URL } from '~/config';
import { isNonNullable } from '~/utils/isNonNullable';
export const SentryInitEffect = () => { export const SentryInitEffect = () => {
const sentryConfig = useRecoilValue(sentryConfigState); const sentryConfig = useRecoilValue(sentryConfigState);
@ -18,7 +20,7 @@ export const SentryInitEffect = () => {
const [isSentryInitialized, setIsSentryInitialized] = useState(false); const [isSentryInitialized, setIsSentryInitialized] = useState(false);
useEffect(() => { useEffect(() => {
if (sentryConfig?.dsn && !isSentryInitialized) { if (isNonEmptyString(sentryConfig?.dsn) && !isSentryInitialized) {
Sentry.init({ Sentry.init({
dsn: sentryConfig?.dsn, dsn: sentryConfig?.dsn,
integrations: [ integrations: [
@ -38,7 +40,7 @@ export const SentryInitEffect = () => {
setIsSentryInitialized(true); setIsSentryInitialized(true);
} }
if (currentUser) { if (isNonNullable(currentUser)) {
Sentry.setUser({ Sentry.setUser({
email: currentUser?.email, email: currentUser?.email,
id: currentUser?.id, id: currentUser?.id,

View File

@ -1,5 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { ApolloClient, InMemoryCache } from '@apollo/client'; import { ApolloClient, InMemoryCache } from '@apollo/client';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { tokenPairState } from '@/auth/states/tokenPairState'; import { tokenPairState } from '@/auth/states/tokenPairState';
@ -14,7 +15,7 @@ export const ApolloMetadataClientProvider = ({
}) => { }) => {
const [tokenPair] = useRecoilState(tokenPairState); const [tokenPair] = useRecoilState(tokenPairState);
const apolloMetadataClient = useMemo(() => { const apolloMetadataClient = useMemo(() => {
if (tokenPair?.accessToken.token) { if (isNonEmptyString(tokenPair?.accessToken.token)) {
return new ApolloClient({ return new ApolloClient({
uri: `${REACT_APP_SERVER_BASE_URL}/metadata`, uri: `${REACT_APP_SERVER_BASE_URL}/metadata`,
cache: new InMemoryCache(), cache: new InMemoryCache(),

View File

@ -12,7 +12,7 @@ export const ObjectMetadataItemsProvider = ({
const objectMetadataItems = useRecoilValue(objectMetadataItemsState); const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const shouldDisplayChildren = () => { const shouldDisplayChildren = () => {
if (objectMetadataItems.length) { if (objectMetadataItems.length > 0) {
return true; return true;
} }
return !currentWorkspaceMember; return !currentWorkspaceMember;

View File

@ -1,5 +1,6 @@
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition'; import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { ObjectMetadataItem } from '../types/ObjectMetadataItem'; import { ObjectMetadataItem } from '../types/ObjectMetadataItem';
@ -31,7 +32,7 @@ export const formatFieldMetadataItemsAsFilterDefinitions = ({
} }
if (field.type === FieldMetadataType.Relation) { if (field.type === FieldMetadataType.Relation) {
if (field.fromRelationMetadata) { if (isNonNullable(field.fromRelationMetadata)) {
return acc; return acc;
} }
} }

View File

@ -3,6 +3,7 @@ import { OrderBy } from '@/object-metadata/types/OrderBy';
import { OrderByField } from '@/object-metadata/types/OrderByField'; import { OrderByField } from '@/object-metadata/types/OrderByField';
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
export const getObjectOrderByField = ( export const getObjectOrderByField = (
objectMetadataItem: ObjectMetadataItem, objectMetadataItem: ObjectMetadataItem,
@ -11,7 +12,7 @@ export const getObjectOrderByField = (
const labelIdentifierFieldMetadata = const labelIdentifierFieldMetadata =
getLabelIdentifierFieldMetadataItem(objectMetadataItem); getLabelIdentifierFieldMetadataItem(objectMetadataItem);
if (labelIdentifierFieldMetadata) { if (isNonNullable(labelIdentifierFieldMetadata)) {
switch (labelIdentifierFieldMetadata.type) { switch (labelIdentifierFieldMetadata.type) {
case FieldMetadataType.FullName: case FieldMetadataType.FullName:
return { return {

View File

@ -3,6 +3,7 @@ import { gql, useApolloClient } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery'; import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const useGetRecordFromCache = ({ export const useGetRecordFromCache = ({
@ -17,7 +18,7 @@ export const useGetRecordFromCache = ({
recordId: string, recordId: string,
cache = apolloClient.cache, cache = apolloClient.cache,
) => { ) => {
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return null; return null;
} }

View File

@ -3,6 +3,7 @@ import { Modifiers } from '@apollo/client/cache';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const useModifyRecordFromCache = ({ export const useModifyRecordFromCache = ({
@ -16,7 +17,7 @@ export const useModifyRecordFromCache = ({
recordId: string, recordId: string,
fieldModifiers: Modifiers<CachedObjectRecord>, fieldModifiers: Modifiers<CachedObjectRecord>,
) => { ) => {
if (!objectMetadataItem) return; if (isNullable(objectMetadataItem)) return;
const cachedRecordId = cache.identify({ const cachedRecordId = cache.identify({
__typename: capitalize(objectMetadataItem.nameSingular), __typename: capitalize(objectMetadataItem.nameSingular),

View File

@ -5,6 +5,7 @@ import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMeta
import { useAddRecordInCache } from '@/object-record/cache/hooks/useAddRecordInCache'; import { useAddRecordInCache } from '@/object-record/cache/hooks/useAddRecordInCache';
import { useGenerateObjectRecordOptimisticResponse } from '@/object-record/cache/hooks/useGenerateObjectRecordOptimisticResponse'; import { useGenerateObjectRecordOptimisticResponse } from '@/object-record/cache/hooks/useGenerateObjectRecordOptimisticResponse';
import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isNonNullable } from '~/utils/isNonNullable';
export const useCreateManyRecordsInCache = <T extends ObjectRecord>({ export const useCreateManyRecordsInCache = <T extends ObjectRecord>({
objectNameSingular, objectNameSingular,
@ -34,7 +35,7 @@ export const useCreateManyRecordsInCache = <T extends ObjectRecord>({
const generatedCachedObjectRecord = const generatedCachedObjectRecord =
generateObjectRecordOptimisticResponse<T>(record); generateObjectRecordOptimisticResponse<T>(record);
if (generatedCachedObjectRecord) { if (isNonNullable(generatedCachedObjectRecord)) {
addRecordInCache(generatedCachedObjectRecord); addRecordInCache(generatedCachedObjectRecord);
createdRecordsInCache.push(generatedCachedObjectRecord); createdRecordsInCache.push(generatedCachedObjectRecord);

View File

@ -14,6 +14,7 @@ import { ObjectRecordEdge } from '@/object-record/types/ObjectRecordEdge';
import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables'; import { ObjectRecordQueryVariables } from '@/object-record/types/ObjectRecordQueryVariables';
import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor'; import { filterUniqueRecordEdgesByCursor } from '@/object-record/utils/filterUniqueRecordEdgesByCursor';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { isNonNullable } from '~/utils/isNonNullable';
import { logError } from '~/utils/logError'; import { logError } from '~/utils/logError';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
@ -84,7 +85,7 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
onCompleted?.(data[objectMetadataItem.namePlural], pageInfo); onCompleted?.(data[objectMetadataItem.namePlural], pageInfo);
if (data?.[objectMetadataItem.namePlural]) { if (isNonNullable(data?.[objectMetadataItem.namePlural])) {
setLastCursor(pageInfo.endCursor ?? ''); setLastCursor(pageInfo.endCursor ?? '');
setHasNextPage(pageInfo.hasNextPage ?? false); setHasNextPage(pageInfo.hasNextPage ?? false);
} }
@ -131,7 +132,7 @@ export const useFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
const pageInfo = const pageInfo =
fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo; fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo;
if (data?.[objectMetadataItem.namePlural]) { if (isNonNullable(data?.[objectMetadataItem.namePlural])) {
setLastCursor(pageInfo.endCursor ?? ''); setLastCursor(pageInfo.endCursor ?? '');
setHasNextPage(pageInfo.hasNextPage ?? false); setHasNextPage(pageInfo.hasNextPage ?? false);
} }

View File

@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery'; import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getCreateManyRecordsMutationResponseField = ( export const getCreateManyRecordsMutationResponseField = (
@ -16,7 +17,7 @@ export const useGenerateCreateManyRecordMutation = ({
}) => { }) => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery'; import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getCreateOneRecordMutationResponseField = ( export const getCreateOneRecordMutationResponseField = (
@ -16,7 +17,7 @@ export const useGenerateCreateOneRecordMutation = ({
}) => { }) => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -2,6 +2,7 @@ import { gql } from '@apollo/client';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getDeleteManyRecordsMutationResponseField = ( export const getDeleteManyRecordsMutationResponseField = (
@ -13,7 +14,7 @@ export const useGenerateDeleteManyRecordMutation = ({
}: { }: {
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
}) => { }) => {
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery'; import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getExecuteQuickActionOnOneRecordMutationGraphQLField = ({ export const getExecuteQuickActionOnOneRecordMutationGraphQLField = ({
@ -20,7 +21,7 @@ export const useGenerateExecuteQuickActionOnOneRecordMutation = ({
}) => { }) => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -3,6 +3,7 @@ import { gql } from '@apollo/client';
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery'; import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getUpdateOneRecordMutationResponseField = ( export const getUpdateOneRecordMutationResponseField = (
@ -16,7 +17,7 @@ export const useGenerateUpdateOneRecordMutation = ({
}) => { }) => {
const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery(); const mapFieldMetadataToGraphQLQuery = useMapFieldMetadataToGraphQLQuery();
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -2,6 +2,7 @@ import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { isNonNullable } from '~/utils/isNonNullable';
import { getOperandLabel } from '../utils/getOperandLabel'; import { getOperandLabel } from '../utils/getOperandLabel';
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType'; import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
@ -24,7 +25,10 @@ export const ObjectFilterDropdownOperandSelect = () => {
setSelectedOperandInDropdown(newOperand); setSelectedOperandInDropdown(newOperand);
setIsObjectFilterDropdownOperandSelectUnfolded(false); setIsObjectFilterDropdownOperandSelectUnfolded(false);
if (filterDefinitionUsedInDropdown && selectedFilter) { if (
isNonNullable(filterDefinitionUsedInDropdown) &&
isNonNullable(selectedFilter)
) {
selectFilter?.({ selectFilter?.({
fieldMetadataId: selectedFilter.fieldMetadataId, fieldMetadataId: selectedFilter.fieldMetadataId,
displayValue: selectedFilter.displayValue, displayValue: selectedFilter.displayValue,

View File

@ -5,6 +5,7 @@ import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataIt
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown'; import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
import { useOptionsForSelect } from '@/object-record/object-filter-dropdown/hooks/useOptionsForSelect'; import { useOptionsForSelect } from '@/object-record/object-filter-dropdown/hooks/useOptionsForSelect';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
import { isNonNullable } from '~/utils/isNonNullable';
export const EMPTY_FILTER_VALUE = ''; export const EMPTY_FILTER_VALUE = '';
export const MAX_OPTIONS_TO_DISPLAY = 3; export const MAX_OPTIONS_TO_DISPLAY = 3;
@ -31,7 +32,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
>([]); >([]);
useEffect(() => { useEffect(() => {
if (selectOptions) { if (isNonNullable(selectOptions)) {
const options = selectOptions.map((option) => { const options = selectOptions.map((option) => {
const isSelected = const isSelected =
objectFilterDropdownSelectedOptionValues?.includes(option.value) ?? objectFilterDropdownSelectedOptionValues?.includes(option.value) ??
@ -70,7 +71,10 @@ export const ObjectFilterDropdownOptionSelect = () => {
? `${selectedOptions.length} options` ? `${selectedOptions.length} options`
: selectedOptions.map((option) => option.label).join(', '); : selectedOptions.map((option) => option.label).join(', ');
if (filterDefinitionUsedInDropdown && selectedOperandInDropdown) { if (
isNonNullable(filterDefinitionUsedInDropdown) &&
isNonNullable(selectedOperandInDropdown)
) {
const newFilterValue = const newFilterValue =
selectedOptions.length > 0 selectedOptions.length > 0
? JSON.stringify(selectedOptions.map((option) => option.value)) ? JSON.stringify(selectedOptions.map((option) => option.value))

View File

@ -2,6 +2,7 @@ import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/
import { MultipleRecordSelectDropdown } from '@/object-record/select/components/MultipleRecordSelectDropdown'; import { MultipleRecordSelectDropdown } from '@/object-record/select/components/MultipleRecordSelectDropdown';
import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect'; import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect';
import { SelectableRecord } from '@/object-record/select/types/SelectableRecord'; import { SelectableRecord } from '@/object-record/select/types/SelectableRecord';
import { isNonNullable } from '~/utils/isNonNullable';
export const EMPTY_FILTER_VALUE = '[]'; export const EMPTY_FILTER_VALUE = '[]';
export const MAX_RECORDS_TO_DISPLAY = 3; export const MAX_RECORDS_TO_DISPLAY = 3;
@ -66,7 +67,10 @@ export const ObjectFilterDropdownRecordSelect = () => {
? `${selectedRecordNames.length} companies` ? `${selectedRecordNames.length} companies`
: selectedRecordNames.join(', '); : selectedRecordNames.join(', ');
if (filterDefinitionUsedInDropdown && selectedOperandInDropdown) { if (
isNonNullable(filterDefinitionUsedInDropdown) &&
isNonNullable(selectedOperandInDropdown)
) {
const newFilterValue = const newFilterValue =
newSelectedRecordIds.length > 0 newSelectedRecordIds.length > 0
? JSON.stringify(newSelectedRecordIds) ? JSON.stringify(newSelectedRecordIds)

View File

@ -2,6 +2,7 @@ import { OrderBy } from '@/object-metadata/types/OrderBy';
import { OrderByField } from '@/object-metadata/types/OrderByField'; import { OrderByField } from '@/object-metadata/types/OrderByField';
import { Field } from '~/generated/graphql'; import { Field } from '~/generated/graphql';
import { mapArrayToObject } from '~/utils/array/mapArrayToObject'; import { mapArrayToObject } from '~/utils/array/mapArrayToObject';
import { isNullable } from '~/utils/isNullable';
import { Sort } from '../types/Sort'; import { Sort } from '../types/Sort';
@ -14,7 +15,7 @@ export const turnSortsIntoOrderBy = (
sorts.map((sort) => { sorts.map((sort) => {
const correspondingField = fieldsById[sort.fieldMetadataId]; const correspondingField = fieldsById[sort.fieldMetadataId];
if (!correspondingField) { if (isNullable(correspondingField)) {
throw new Error( throw new Error(
`Could not find field ${sort.fieldMetadataId} in metadata object`, `Could not find field ${sort.fieldMetadataId} in metadata object`,
); );

View File

@ -19,6 +19,7 @@ import { actionBarEntriesState } from '@/ui/navigation/action-bar/states/actionB
import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState'; import { contextMenuEntriesState } from '@/ui/navigation/context-menu/states/contextMenuEntriesState';
import { ContextMenuEntry } from '@/ui/navigation/context-menu/types/ContextMenuEntry'; import { ContextMenuEntry } from '@/ui/navigation/context-menu/types/ContextMenuEntry';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { isNonNullable } from '~/utils/isNonNullable';
type useRecordActionBarProps = { type useRecordActionBarProps = {
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
@ -62,7 +63,7 @@ export const useRecordActionBar = ({
if (isFavorite) { if (isFavorite) {
deleteFavorite(foundFavorite.id); deleteFavorite(foundFavorite.id);
} else if (selectedRecord) { } else if (isNonNullable(selectedRecord)) {
createFavorite(selectedRecord, objectMetadataItem.nameSingular); createFavorite(selectedRecord, objectMetadataItem.nameSingular);
} }
callback?.(); callback?.();

View File

@ -80,7 +80,7 @@ export const recordBoardColumnsFamilySelectorScopeMap =
true, true,
); );
if (lastColumn) { if (isNonNullable(lastColumn)) {
set( set(
isLastRecordBoardColumnFamilyStateScopeMap({ isLastRecordBoardColumnFamilyStateScopeMap({
scopeId, scopeId,
@ -100,7 +100,7 @@ export const recordBoardColumnsFamilySelectorScopeMap =
true, true,
); );
if (firstColumn) { if (isNonNullable(firstColumn)) {
set( set(
isFirstRecordBoardColumnFamilyStateScopeMap({ isFirstRecordBoardColumnFamilyStateScopeMap({
scopeId, scopeId,

View File

@ -3,6 +3,7 @@ import { useContext } from 'react';
import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation'; import { isFieldRelation } from '@/object-record/record-field/types/guards/isFieldRelation';
import { IconPencil } from '@/ui/display/icon'; import { IconPencil } from '@/ui/display/icon';
import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { isNullable } from '~/utils/isNullable';
import { FieldContext } from '../contexts/FieldContext'; import { FieldContext } from '../contexts/FieldContext';
import { isFieldEmail } from '../types/guards/isFieldEmail'; import { isFieldEmail } from '../types/guards/isFieldEmail';
@ -12,7 +13,7 @@ import { isFieldPhone } from '../types/guards/isFieldPhone';
export const useGetButtonIcon = (): IconComponent | undefined => { export const useGetButtonIcon = (): IconComponent | undefined => {
const { fieldDefinition } = useContext(FieldContext); const { fieldDefinition } = useContext(FieldContext);
if (!fieldDefinition) return undefined; if (isNullable(fieldDefinition)) return undefined;
if ( if (
isFieldLink(fieldDefinition) || isFieldLink(fieldDefinition) ||

View File

@ -9,6 +9,7 @@ import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/Dropdow
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
import { MenuItemSelectTag } from '@/ui/navigation/menu-item/components/MenuItemSelectTag'; import { MenuItemSelectTag } from '@/ui/navigation/menu-item/components/MenuItemSelectTag';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isNonNullable } from '~/utils/isNonNullable';
const StyledRelationPickerContainer = styled.div` const StyledRelationPickerContainer = styled.div`
left: -1px; left: -1px;
@ -52,7 +53,7 @@ export const SelectFieldInput = ({
event.target instanceof HTMLInputElement && event.target instanceof HTMLInputElement &&
event.target.tagName === 'INPUT' event.target.tagName === 'INPUT'
); );
if (weAreNotInAnHTMLInput && onCancel) { if (weAreNotInAnHTMLInput && isNonNullable(onCancel)) {
onCancel(); onCancel();
} }
}, },

View File

@ -74,7 +74,7 @@ const tabJestFn = fn();
const shiftTabJestFn = fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
enterJestFn.mockClear(); enterJestFn.mockClear();
escapeJestfn.mockClear(); escapeJestfn.mockClear();
clickOutsideJestFn.mockClear(); clickOutsideJestFn.mockClear();

View File

@ -74,7 +74,7 @@ const tabJestFn = fn();
const shiftTabJestFn = fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
enterJestFn.mockClear(); enterJestFn.mockClear();
escapeJestfn.mockClear(); escapeJestfn.mockClear();
clickOutsideJestFn.mockClear(); clickOutsideJestFn.mockClear();

View File

@ -75,7 +75,7 @@ const tabJestFn = fn();
const shiftTabJestFn = fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
enterJestFn.mockClear(); enterJestFn.mockClear();
escapeJestfn.mockClear(); escapeJestfn.mockClear();
clickOutsideJestFn.mockClear(); clickOutsideJestFn.mockClear();

View File

@ -4,6 +4,7 @@ import { expect, fn, userEvent, waitFor, within } from '@storybook/test';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { FieldRatingValue } from '../../../../types/FieldMetadata'; import { FieldRatingValue } from '../../../../types/FieldMetadata';
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider'; import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
@ -62,7 +63,7 @@ const RatingFieldInputWithContext = ({
const submitJestFn = fn(); const submitJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
submitJestFn.mockClear(); submitJestFn.mockClear();
} }
return <Story />; return <Story />;
@ -100,7 +101,7 @@ export const Submit: Story = {
const firstStar = input.firstElementChild; const firstStar = input.firstElementChild;
await waitFor(() => { await waitFor(() => {
if (firstStar) { if (isNonNullable(firstStar)) {
userEvent.click(firstStar); userEvent.click(firstStar);
expect(submitJestFn).toHaveBeenCalledTimes(1); expect(submitJestFn).toHaveBeenCalledTimes(1);
} }

View File

@ -88,7 +88,7 @@ const submitJestFn = fn();
const cancelJestFn = fn(); const cancelJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
submitJestFn.mockClear(); submitJestFn.mockClear();
cancelJestFn.mockClear(); cancelJestFn.mockClear();
} }

View File

@ -74,7 +74,7 @@ const tabJestFn = fn();
const shiftTabJestFn = fn(); const shiftTabJestFn = fn();
const clearMocksDecorator: Decorator = (Story, context) => { const clearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
enterJestFn.mockClear(); enterJestFn.mockClear();
escapeJestfn.mockClear(); escapeJestfn.mockClear();
clickOutsideJestFn.mockClear(); clickOutsideJestFn.mockClear();

View File

@ -136,7 +136,7 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
}); });
break; break;
case ViewFilterOperand.IsNot: case ViewFilterOperand.IsNot:
if (parsedRecordIds.length) { if (parsedRecordIds.length > 0) {
objectRecordFilters.push({ objectRecordFilters.push({
not: { not: {
[correspondingField.name + 'Id']: { [correspondingField.name + 'Id']: {

View File

@ -4,6 +4,7 @@ import { useColumnDefinitionsFromFieldMetadata } from '@/object-metadata/hooks/u
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural'; import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
import { useViewBar } from '@/views/hooks/useViewBar'; import { useViewBar } from '@/views/hooks/useViewBar';
import { isNullable } from '~/utils/isNullable';
type RecordIndexViewBarEffectProps = { type RecordIndexViewBarEffectProps = {
objectNamePlural: string; objectNamePlural: string;
@ -33,7 +34,7 @@ export const RecordIndexViewBarEffect = ({
} = useViewBar({ viewBarId }); } = useViewBar({ viewBarId });
useEffect(() => { useEffect(() => {
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return; return;
} }
setViewObjectMetadataId?.(objectMetadataItem.id); setViewObjectMetadataId?.(objectMetadataItem.id);

View File

@ -6,6 +6,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates';
import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition';
import { isNonNullable } from '~/utils/isNonNullable';
import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable'; import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable';
@ -52,7 +53,7 @@ export const generateCsv: GenerateExport = ({
return hasSubFields; return hasSubFields;
}); });
if (fieldsWithSubFields) { if (isNonNullable(fieldsWithSubFields)) {
const nestedFieldsWithoutTypename = Object.keys( const nestedFieldsWithoutTypename = Object.keys(
(fieldsWithSubFields as any)[column.field], (fieldsWithSubFields as any)[column.field],
) )

View File

@ -20,7 +20,7 @@ const StyledRecordInlineCellNormalModeOuterContainer = styled.div<
padding: ${({ theme }) => theme.spacing(1)}; padding: ${({ theme }) => theme.spacing(1)};
${(props) => { ${(props) => {
if (props.isHovered) { if (props.isHovered === true) {
return css` return css`
background-color: ${!props.disableHoverEffect background-color: ${!props.disableHoverEffect
? props.theme.background.transparent.light ? props.theme.background.transparent.light

View File

@ -5,6 +5,7 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext
import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput'; import { useRecordFieldInput } from '@/object-record/record-field/hooks/useRecordFieldInput';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { isNonNullable } from '~/utils/isNonNullable';
import { isInlineCellInEditModeScopedState } from '../states/isInlineCellInEditModeScopedState'; import { isInlineCellInEditModeScopedState } from '../states/isInlineCellInEditModeScopedState';
import { InlineCellHotkeyScope } from '../types/InlineCellHotkeyScope'; import { InlineCellHotkeyScope } from '../types/InlineCellHotkeyScope';
@ -39,7 +40,7 @@ export const useInlineCell = () => {
setIsInlineCellInEditMode(true); setIsInlineCellInEditMode(true);
initFieldInputDraftValue(); initFieldInputDraftValue();
if (customEditHotkeyScopeForField) { if (isNonNullable(customEditHotkeyScopeForField)) {
setHotkeyScopeAndMemorizePreviousScope( setHotkeyScopeAndMemorizePreviousScope(
customEditHotkeyScopeForField.scope, customEditHotkeyScopeForField.scope,
customEditHotkeyScopeForField.customScopes, customEditHotkeyScopeForField.customScopes,

View File

@ -31,6 +31,7 @@ import {
useUploadImageMutation, useUploadImageMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable'; import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
type RecordShowContainerProps = { type RecordShowContainerProps = {
objectNameSingular: string; objectNameSingular: string;
@ -92,7 +93,7 @@ export const RecordShowContainer = ({
if (!avatarUrl) { if (!avatarUrl) {
return; return;
} }
if (!updateOneRecord) { if (isNullable(updateOneRecord)) {
return; return;
} }
if (!recordFromStore) { if (!recordFromStore) {

View File

@ -15,6 +15,7 @@ import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkey
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState'; import { contextMenuIsOpenState } from '@/ui/navigation/context-menu/states/contextMenuIsOpenState';
import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState'; import { contextMenuPositionState } from '@/ui/navigation/context-menu/states/contextMenuPositionState';
import { isNullable } from '~/utils/isNullable';
const StyledContainer = styled.td<{ isSelected: boolean }>` const StyledContainer = styled.td<{ isSelected: boolean }>`
background: ${({ isSelected, theme }) => background: ${({ isSelected, theme }) =>
@ -45,7 +46,7 @@ export const RecordTableCellContainer = () => {
const updateRecord = useContext(RecordUpdateContext); const updateRecord = useContext(RecordUpdateContext);
if (!columnDefinition) { if (isNullable(columnDefinition)) {
return null; return null;
} }

View File

@ -37,7 +37,7 @@ const StyledColumnHeaderCell = styled.th<{
`; `;
}}; }};
${({ isResizing, theme }) => { ${({ isResizing, theme }) => {
if (isResizing) { if (isResizing === true) {
return `&:after { return `&:after {
background-color: ${theme.color.blue}; background-color: ${theme.color.blue};
bottom: 0; bottom: 0;

View File

@ -11,6 +11,7 @@ import { useLeaveTableFocus } from '@/object-record/record-table/hooks/internal/
import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect'; import { useDragSelect } from '@/ui/utilities/drag-select/hooks/useDragSelect';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope'; import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { isNonNullable } from '~/utils/isNonNullable';
import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext'; import { CellHotkeyScopeContext } from '../../contexts/CellHotkeyScopeContext';
import { TableHotkeyScope } from '../../types/TableHotkeyScope'; import { TableHotkeyScope } from '../../types/TableHotkeyScope';
@ -56,7 +57,7 @@ export const useOpenRecordTableCell = () => {
initFieldInputDraftValue(options?.initialValue); initFieldInputDraftValue(options?.initialValue);
if (customCellHotkeyScope) { if (isNonNullable(customCellHotkeyScope)) {
setHotkeyScope( setHotkeyScope(
customCellHotkeyScope.scope, customCellHotkeyScope.scope,
customCellHotkeyScope.customScopes, customCellHotkeyScope.customScopes,

View File

@ -19,6 +19,7 @@ import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownM
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem'; import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList'; import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem'; import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
import { isNonNullable } from '~/utils/isNonNullable';
export const StyledSelectableItem = styled(SelectableItem)` export const StyledSelectableItem = styled(SelectableItem)`
height: 100%; height: 100%;
@ -152,7 +153,7 @@ export const MultipleObjectRecordSelect = ({
(entity) => entity.record.id === recordId, (entity) => entity.record.id === recordId,
); );
if (correspondingRecordForSelect) { if (isNonNullable(correspondingRecordForSelect)) {
handleSelectChange( handleSelectChange(
correspondingRecordForSelect, correspondingRecordForSelect,
!recordIsSelected, !recordIsSelected,

View File

@ -6,6 +6,7 @@ import {
} from '@/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch'; } from '@/object-record/relation-picker/components/SingleEntitySelectMenuItemsWithSearch';
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu'; import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { isNonNullable } from '~/utils/isNonNullable';
export type SingleEntitySelectProps = { export type SingleEntitySelectProps = {
disableBackgroundBlur?: boolean; disableBackgroundBlur?: boolean;
@ -37,7 +38,7 @@ export const SingleEntitySelect = ({
event.target instanceof HTMLInputElement && event.target instanceof HTMLInputElement &&
event.target.tagName === 'INPUT' event.target.tagName === 'INPUT'
); );
if (weAreNotInAnHTMLInput && onCancel) { if (weAreNotInAnHTMLInput && isNonNullable(onCancel)) {
onCancel(); onCancel();
} }
}, },

View File

@ -76,7 +76,7 @@ export const SingleEntitySelectMenuItems = ({
selectableItemIdArray={selectableItemIds} selectableItemIdArray={selectableItemIds}
hotkeyScope={RelationPickerHotkeyScope.RelationPicker} hotkeyScope={RelationPickerHotkeyScope.RelationPicker}
onEnter={(itemId) => { onEnter={(itemId) => {
if (showCreateButton) { if (showCreateButton === true) {
onCreate?.(); onCreate?.();
} else { } else {
const entity = entitiesInDropdown.findIndex( const entity = entitiesInDropdown.findIndex(

View File

@ -1,3 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem'; import { getLabelIdentifierFieldMetadataItem } from '@/object-metadata/utils/getLabelIdentifierFieldMetadataItem';
import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter'; import { ObjectRecordQueryFilter } from '@/object-record/record-filter/types/ObjectRecordQueryFilter';
@ -23,10 +25,10 @@ export const useSearchFilterPerMetadataItem = ({
let searchFilter: ObjectRecordQueryFilter = {}; let searchFilter: ObjectRecordQueryFilter = {};
if (labelIdentifierFieldMetadataItem) { if (isNonNullable(labelIdentifierFieldMetadataItem)) {
switch (labelIdentifierFieldMetadataItem.type) { switch (labelIdentifierFieldMetadataItem.type) {
case FieldMetadataType.FullName: { case FieldMetadataType.FullName: {
if (searchFilterValue) { if (isNonEmptyString(searchFilterValue)) {
const fullNameFilter = makeOrFilterVariables([ const fullNameFilter = makeOrFilterVariables([
{ {
[labelIdentifierFieldMetadataItem.name]: { [labelIdentifierFieldMetadataItem.name]: {
@ -44,14 +46,14 @@ export const useSearchFilterPerMetadataItem = ({
}, },
]); ]);
if (fullNameFilter) { if (isNonNullable(fullNameFilter)) {
searchFilter = fullNameFilter; searchFilter = fullNameFilter;
} }
} }
break; break;
} }
default: { default: {
if (searchFilterValue) { if (isNonEmptyString(searchFilterValue)) {
searchFilter = { searchFilter = {
[labelIdentifierFieldMetadataItem.name]: { [labelIdentifierFieldMetadataItem.name]: {
ilike: `%${searchFilterValue}%`, ilike: `%${searchFilterValue}%`,

View File

@ -56,7 +56,7 @@ export const useRecordsForSelect = ({
fieldNames.map((fieldName) => { fieldNames.map((fieldName) => {
const [parentFieldName, subFieldName] = fieldName.split('.'); const [parentFieldName, subFieldName] = fieldName.split('.');
if (subFieldName) { if (isNonEmptyString(subFieldName)) {
// Composite field // Composite field
return { return {
[parentFieldName]: { [parentFieldName]: {

View File

@ -1,3 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords'; import { useCreateManyRecords } from '@/object-record/hooks/useCreateManyRecords';
import { getSpreadSheetValidation } from '@/object-record/spreadsheet-import/util/getSpreadSheetValidation'; import { getSpreadSheetValidation } from '@/object-record/spreadsheet-import/util/getSpreadSheetValidation';
@ -7,6 +9,7 @@ import { useIcons } from '@/ui/display/icon/hooks/useIcons';
import { IconComponent } from '@/ui/display/icon/types/IconComponent'; import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
const firstName = 'Firstname'; const firstName = 'Firstname';
const lastName = 'Lastname'; const lastName = 'Lastname';
@ -128,14 +131,19 @@ export const useSpreadsheetRecordImport = (objectNameSingular: string) => {
} }
break; break;
case FieldMetadataType.Relation: case FieldMetadataType.Relation:
if (value) { if (
isNonNullable(value) &&
(isNonEmptyString(value) || value !== false)
) {
fieldMapping[field.name + 'Id'] = value; fieldMapping[field.name + 'Id'] = value;
} }
break; break;
case FieldMetadataType.FullName: case FieldMetadataType.FullName:
if ( if (
record[`${firstName} (${field.name})`] || isNonNullable(
record[`${lastName} (${field.name})`] record[`${firstName} (${field.name})`] ||
record[`${lastName} (${field.name})`],
)
) { ) {
fieldMapping[field.name] = { fieldMapping[field.name] = {
firstName: record[`${firstName} (${field.name})`] || '', firstName: record[`${firstName} (${field.name})`] || '',

View File

@ -2,6 +2,7 @@ import { gql } from '@apollo/client';
import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem'; import { EMPTY_MUTATION } from '@/object-metadata/hooks/useObjectMetadataItem';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { isNullable } from '~/utils/isNullable';
import { capitalize } from '~/utils/string/capitalize'; import { capitalize } from '~/utils/string/capitalize';
export const getDeleteOneRecordMutationResponseField = ( export const getDeleteOneRecordMutationResponseField = (
@ -13,7 +14,7 @@ export const generateDeleteOneRecordMutation = ({
}: { }: {
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
}) => { }) => {
if (!objectMetadataItem) { if (isNullable(objectMetadataItem)) {
return EMPTY_MUTATION; return EMPTY_MUTATION;
} }

View File

@ -59,7 +59,7 @@ export const useFilteredSearchEntityQuery = ({
fieldNames.map((fieldName) => { fieldNames.map((fieldName) => {
const [parentFieldName, subFieldName] = fieldName.split('.'); const [parentFieldName, subFieldName] = fieldName.split('.');
if (subFieldName) { if (isNonEmptyString(subFieldName)) {
// Composite field // Composite field
return { return {
[parentFieldName]: { [parentFieldName]: {

View File

@ -55,7 +55,7 @@ export const SettingsAccountsListCard = <
const theme = useTheme(); const theme = useTheme();
const navigate = useNavigate(); const navigate = useNavigate();
if (isLoading) return <SettingsAccountsListSkeletonCard />; if (isLoading === true) return <SettingsAccountsListSkeletonCard />;
if (!accounts.length) return <SettingsAccountsListEmptyStateCard />; if (!accounts.length) return <SettingsAccountsListEmptyStateCard />;

View File

@ -7,7 +7,7 @@ import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
const updateBlockedEmailListJestFn = fn(); const updateBlockedEmailListJestFn = fn();
const ClearMocksDecorator: Decorator = (Story, context) => { const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
updateBlockedEmailListJestFn.mockClear(); updateBlockedEmailListJestFn.mockClear();
} }
return <Story />; return <Story />;

View File

@ -9,7 +9,7 @@ import { formatToHumanReadableDate } from '~/utils';
const handleBlockedEmailRemoveJestFn = fn(); const handleBlockedEmailRemoveJestFn = fn();
const ClearMocksDecorator: Decorator = (Story, context) => { const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
handleBlockedEmailRemoveJestFn.mockClear(); handleBlockedEmailRemoveJestFn.mockClear();
} }
return <Story />; return <Story />;

View File

@ -9,7 +9,7 @@ import { formatToHumanReadableDate } from '~/utils';
const onRemoveJestFn = fn(); const onRemoveJestFn = fn();
const ClearMocksDecorator: Decorator = (Story, context) => { const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
onRemoveJestFn.mockClear(); onRemoveJestFn.mockClear();
} }
return <Story />; return <Story />;

View File

@ -9,7 +9,7 @@ const handleActivateMockFunction = fn();
const handleEraseMockFunction = fn(); const handleEraseMockFunction = fn();
const ClearMocksDecorator: Decorator = (Story, context) => { const ClearMocksDecorator: Decorator = (Story, context) => {
if (context.parameters.clearMocks) { if (context.parameters.clearMocks === true) {
handleActivateMockFunction.mockClear(); handleActivateMockFunction.mockClear();
handleEraseMockFunction.mockClear(); handleEraseMockFunction.mockClear();
} }

View File

@ -5,6 +5,7 @@ import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifie
import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm'; import { SettingsObjectFieldSelectFormValues } from '@/settings/data-model/components/SettingsObjectFieldSelectForm';
import { SETTINGS_FIELD_METADATA_TYPES } from '@/settings/data-model/constants/SettingsFieldMetadataTypes'; import { SETTINGS_FIELD_METADATA_TYPES } from '@/settings/data-model/constants/SettingsFieldMetadataTypes';
import { FieldMetadataType } from '~/generated-metadata/graphql'; import { FieldMetadataType } from '~/generated-metadata/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
export const getFieldDefaultPreviewValue = ({ export const getFieldDefaultPreviewValue = ({
fieldMetadataItem, fieldMetadataItem,
@ -21,14 +22,17 @@ export const getFieldDefaultPreviewValue = ({
selectOptions?: SettingsObjectFieldSelectFormValues; selectOptions?: SettingsObjectFieldSelectFormValues;
}) => { }) => {
// Select field // Select field
if (fieldMetadataItem.type === FieldMetadataType.Select && selectOptions) { if (
fieldMetadataItem.type === FieldMetadataType.Select &&
isNonNullable(selectOptions)
) {
return selectOptions.find(({ isDefault }) => isDefault) || selectOptions[0]; return selectOptions.find(({ isDefault }) => isDefault) || selectOptions[0];
} }
// Relation field // Relation field
if ( if (
fieldMetadataItem.type === FieldMetadataType.Relation && fieldMetadataItem.type === FieldMetadataType.Relation &&
relationObjectMetadataItem isNonNullable(relationObjectMetadataItem)
) { ) {
const relationLabelIdentifierFieldMetadataItem = const relationLabelIdentifierFieldMetadataItem =
getLabelIdentifierFieldMetadataItem(relationObjectMetadataItem); getLabelIdentifierFieldMetadataItem(relationObjectMetadataItem);

View File

@ -1,3 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem'; import { ApiFieldItem } from '@/settings/developers/types/api-key/ApiFieldItem';
import { ApiKey } from '@/settings/developers/types/api-key/ApiKey'; import { ApiKey } from '@/settings/developers/types/api-key/ApiKey';
import { beautifyDateDiff } from '~/utils/date-utils'; import { beautifyDateDiff } from '~/utils/date-utils';
@ -7,7 +9,7 @@ export const formatExpiration = (
withExpiresMention: boolean = false, withExpiresMention: boolean = false,
short: boolean = true, short: boolean = true,
) => { ) => {
if (expiresAt) { if (isNonEmptyString(expiresAt)) {
const dateDiff = beautifyDateDiff(expiresAt, undefined, short); const dateDiff = beautifyDateDiff(expiresAt, undefined, short);
if (dateDiff.includes('-')) { if (dateDiff.includes('-')) {
return 'Expired'; return 'Expired';

View File

@ -27,7 +27,7 @@ export const ChangePassword = () => {
email: currentUser.email, email: currentUser.email,
}, },
}); });
if (data?.emailPasswordResetLink?.success) { if (data?.emailPasswordResetLink?.success === true) {
enqueueSnackBar('Password reset link has been sent to the email', { enqueueSnackBar('Password reset link has been sent to the email', {
variant: 'success', variant: 'success',
}); });

View File

@ -47,12 +47,9 @@ export const NameFields = ({
// TODO: Enhance this with react-web-hook-form (https://www.react-hook-form.com) // TODO: Enhance this with react-web-hook-form (https://www.react-hook-form.com)
const debouncedUpdate = debounce(async () => { const debouncedUpdate = debounce(async () => {
if (onFirstNameUpdate) { onFirstNameUpdate?.(firstName);
onFirstNameUpdate(firstName); onLastNameUpdate?.(lastName);
}
if (onLastNameUpdate) {
onLastNameUpdate(lastName);
}
try { try {
if (!currentWorkspaceMember?.id) { if (!currentWorkspaceMember?.id) {
throw new Error('User is not logged in'); throw new Error('User is not logged in');

View File

@ -7,6 +7,8 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { ImageInput } from '@/ui/input/components/ImageInput'; import { ImageInput } from '@/ui/input/components/ImageInput';
import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI'; import { getImageAbsoluteURIOrBase64 } from '@/users/utils/getProfilePictureAbsoluteURI';
import { useUploadProfilePictureMutation } from '~/generated/graphql'; import { useUploadProfilePictureMutation } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
export const ProfilePictureUploader = () => { export const ProfilePictureUploader = () => {
const [uploadPicture, { loading: isUploading }] = const [uploadPicture, { loading: isUploading }] =
@ -25,7 +27,7 @@ export const ProfilePictureUploader = () => {
}); });
const handleUpload = async (file: File) => { const handleUpload = async (file: File) => {
if (!file) { if (isNullable(file)) {
return; return;
} }
@ -72,7 +74,7 @@ export const ProfilePictureUploader = () => {
}; };
const handleAbort = async () => { const handleAbort = async () => {
if (uploadController) { if (isNonNullable(uploadController)) {
uploadController.abort(); uploadController.abort();
setUploadController(null); setUploadController(null);
} }

View File

@ -6,6 +6,8 @@ import { useRecoilValue } from 'recoil';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { TextInput } from '@/ui/input/components/TextInput'; import { TextInput } from '@/ui/input/components/TextInput';
import { useUpdateWorkspaceMutation } from '~/generated/graphql'; import { useUpdateWorkspaceMutation } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
import { logError } from '~/utils/logError'; import { logError } from '~/utils/logError';
const StyledComboInputContainer = styled.div` const StyledComboInputContainer = styled.div`
@ -37,7 +39,7 @@ export const NameField = ({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedUpdate = useCallback( const debouncedUpdate = useCallback(
debounce(async (name: string) => { debounce(async (name: string) => {
if (onNameUpdate) { if (isNonNullable(onNameUpdate)) {
onNameUpdate(displayName); onNameUpdate(displayName);
} }
if (!autoSave || !name) { if (!autoSave || !name) {
@ -52,7 +54,7 @@ export const NameField = ({
}, },
}); });
if (errors || !data?.updateWorkspace) { if (isNonNullable(errors) || isNullable(data?.updateWorkspace)) {
throw errors; throw errors;
} }
} catch (error) { } catch (error) {

View File

@ -7,6 +7,7 @@ import {
useUpdateWorkspaceMutation, useUpdateWorkspaceMutation,
useUploadWorkspaceLogoMutation, useUploadWorkspaceLogoMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { isNullable } from '~/utils/isNullable';
export const WorkspaceLogoUploader = () => { export const WorkspaceLogoUploader = () => {
const [uploadLogo] = useUploadWorkspaceLogoMutation(); const [uploadLogo] = useUploadWorkspaceLogoMutation();
@ -16,7 +17,7 @@ export const WorkspaceLogoUploader = () => {
); );
const onUpload = async (file: File) => { const onUpload = async (file: File) => {
if (!file) { if (isNullable(file)) {
return; return;
} }
if (!currentWorkspace?.id) { if (!currentWorkspace?.id) {

View File

@ -1,6 +1,7 @@
import { createContext } from 'react'; import { createContext } from 'react';
import { SpreadsheetOptions } from '@/spreadsheet-import/types'; import { SpreadsheetOptions } from '@/spreadsheet-import/types';
import { isNullable } from '~/utils/isNullable';
export const RsiContext = createContext({} as any); export const RsiContext = createContext({} as any);
@ -13,7 +14,7 @@ export const Providers = <T extends string>({
children, children,
values, values,
}: ProvidersProps<T>) => { }: ProvidersProps<T>) => {
if (!values.fields) { if (isNullable(values.fields)) {
throw new Error('Fields must be provided to spreadsheet-import'); throw new Error('Fields must be provided to spreadsheet-import');
} }

View File

@ -95,7 +95,7 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
const isSingleSheet = workbook.SheetNames.length === 1; const isSingleSheet = workbook.SheetNames.length === 1;
if (isSingleSheet) { if (isSingleSheet) {
if ( if (
maxRecords && maxRecords > 0 &&
exceedsMaxRecords( exceedsMaxRecords(
workbook.Sheets[workbook.SheetNames[0]], workbook.Sheets[workbook.SheetNames[0]],
maxRecords, maxRecords,
@ -147,7 +147,7 @@ export const UploadFlow = ({ nextStep }: UploadFlowProps) => {
sheetNames={state.workbook.SheetNames} sheetNames={state.workbook.SheetNames}
onContinue={async (sheetName) => { onContinue={async (sheetName) => {
if ( if (
maxRecords && maxRecords > 0 &&
exceedsMaxRecords(state.workbook.Sheets[sheetName], maxRecords) exceedsMaxRecords(state.workbook.Sheets[sheetName], maxRecords)
) { ) {
errorToast( errorToast(

View File

@ -14,6 +14,7 @@ import { useDialogManager } from '@/ui/feedback/dialog-manager/hooks/useDialogMa
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
import { Toggle } from '@/ui/input/components/Toggle'; import { Toggle } from '@/ui/input/components/Toggle';
import { Modal } from '@/ui/layout/modal/components/Modal'; import { Modal } from '@/ui/layout/modal/components/Modal';
import { isNonNullable } from '~/utils/isNonNullable';
import { generateColumns } from './components/columns'; import { generateColumns } from './components/columns';
import { Meta } from './types'; import { Meta } from './types';
@ -94,7 +95,7 @@ export const ValidationStep = <T extends string>({
); );
const deleteSelectedRows = () => { const deleteSelectedRows = () => {
if (selectedRows.size) { if (selectedRows.size > 0) {
const newData = data.filter((value) => !selectedRows.has(value.__index)); const newData = data.filter((value) => !selectedRows.has(value.__index));
updateData(newData); updateData(newData);
setSelectedRows(new Set()); setSelectedRows(new Set());
@ -129,7 +130,7 @@ export const ValidationStep = <T extends string>({
const tableData = useMemo(() => { const tableData = useMemo(() => {
if (filterByErrors) { if (filterByErrors) {
return data.filter((value) => { return data.filter((value) => {
if (value?.__errors) { if (isNonNullable(value?.__errors)) {
return Object.values(value.__errors)?.filter( return Object.values(value.__errors)?.filter(
(err) => err.level === 'error', (err) => err.level === 'error',
).length; ).length;
@ -146,7 +147,7 @@ export const ValidationStep = <T extends string>({
const calculatedData = data.reduce( const calculatedData = data.reduce(
(acc, value) => { (acc, value) => {
const { __index, __errors, ...values } = value; const { __index, __errors, ...values } = value;
if (__errors) { if (isNonNullable(__errors)) {
for (const key in __errors) { for (const key in __errors) {
if (__errors[key].level === 'error') { if (__errors[key].level === 'error') {
acc.invalidData.push(values as unknown as Data<T>); acc.invalidData.push(values as unknown as Data<T>);
@ -165,7 +166,7 @@ export const ValidationStep = <T extends string>({
}; };
const onContinue = () => { const onContinue = () => {
const invalidData = data.find((value) => { const invalidData = data.find((value) => {
if (value?.__errors) { if (isNonNullable(value?.__errors)) {
return !!Object.values(value.__errors)?.filter( return !!Object.values(value.__errors)?.filter(
(err) => err.level === 'error', (err) => err.level === 'error',
).length; ).length;

View File

@ -9,6 +9,7 @@ import { AppTooltip } from '@/ui/display/tooltip/AppTooltip';
import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox'; import { Checkbox, CheckboxVariant } from '@/ui/input/components/Checkbox';
import { TextInput } from '@/ui/input/components/TextInput'; import { TextInput } from '@/ui/input/components/TextInput';
import { Toggle } from '@/ui/input/components/Toggle'; import { Toggle } from '@/ui/input/components/Toggle';
import { isNonNullable } from '~/utils/isNonNullable';
import { Meta } from '../types'; import { Meta } from '../types';
@ -207,7 +208,7 @@ export const generateColumns = <T extends string>(
); );
} }
if (row.__errors?.[columnKey]) { if (isNonNullable(row.__errors?.[columnKey])) {
return ( return (
<> <>
{component} {component}

View File

@ -1,3 +1,4 @@
import { isNonEmptyString } from '@sniptt/guards';
import { v4 } from 'uuid'; import { v4 } from 'uuid';
import { import {
@ -11,6 +12,8 @@ import {
RowHook, RowHook,
TableHook, TableHook,
} from '@/spreadsheet-import/types'; } from '@/spreadsheet-import/types';
import { isNonNullable } from '~/utils/isNonNullable';
import { isNullable } from '~/utils/isNullable';
export const addErrorsAndRunHooks = <T extends string>( export const addErrorsAndRunHooks = <T extends string>(
data: (Data<T> & Partial<Meta>)[], data: (Data<T> & Partial<Meta>)[],
@ -27,11 +30,11 @@ export const addErrorsAndRunHooks = <T extends string>(
}; };
}; };
if (tableHook) { if (isNonNullable(tableHook)) {
data = tableHook(data, addHookError); data = tableHook(data, addHookError);
} }
if (rowHook) { if (isNonNullable(rowHook)) {
data = data.map((value, index) => data = data.map((value, index) =>
rowHook(value, (...props) => addHookError(index, ...props), data), rowHook(value, (...props) => addHookError(index, ...props), data),
); );
@ -47,7 +50,10 @@ export const addErrorsAndRunHooks = <T extends string>(
const duplicates = new Set(); // Set of items used multiple times const duplicates = new Set(); // Set of items used multiple times
values.forEach((value) => { values.forEach((value) => {
if (validation.allowEmpty && !value) { if (
validation.allowEmpty === true &&
(isNullable(value) || value === '' || !value)
) {
// If allowEmpty is set, we will not validate falsy fields such as undefined or empty string. // If allowEmpty is set, we will not validate falsy fields such as undefined or empty string.
return; return;
} }
@ -95,7 +101,7 @@ export const addErrorsAndRunHooks = <T extends string>(
data.forEach((entry, index) => { data.forEach((entry, index) => {
const value = entry[field.key]?.toString(); const value = entry[field.key]?.toString();
if (value && !value.match(regex)) { if (isNonEmptyString(value) && !value.match(regex)) {
errors[index] = { errors[index] = {
...errors[index], ...errors[index],
[field.key]: { [field.key]: {
@ -113,7 +119,7 @@ export const addErrorsAndRunHooks = <T extends string>(
data.forEach((entry, index) => { data.forEach((entry, index) => {
const value = entry[field.key]?.toString(); const value = entry[field.key]?.toString();
if (value && !validation.isValid(value)) { if (isNonEmptyString(value) && !validation.isValid(value)) {
errors[index] = { errors[index] = {
...errors[index], ...errors[index],
[field.key]: { [field.key]: {
@ -136,10 +142,10 @@ export const addErrorsAndRunHooks = <T extends string>(
} }
const newValue = value as Data<T> & Meta; const newValue = value as Data<T> & Meta;
if (errors[index]) { if (isNonNullable(errors[index])) {
return { ...newValue, __errors: errors[index] }; return { ...newValue, __errors: errors[index] };
} }
if (!errors[index] && value?.__errors) { if (isNullable(errors[index]) && isNonNullable(value?.__errors)) {
return { ...newValue, __errors: null }; return { ...newValue, __errors: null };
} }
return newValue; return newValue;

View File

@ -6,6 +6,7 @@ import {
MatchColumnsStepProps, MatchColumnsStepProps,
} from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep'; } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import { Field, Fields } from '@/spreadsheet-import/types'; import { Field, Fields } from '@/spreadsheet-import/types';
import { isNonNullable } from '~/utils/isNonNullable';
import { findMatch } from './findMatch'; import { findMatch } from './findMatch';
import { setColumn } from './setColumn'; import { setColumn } from './setColumn';
@ -18,7 +19,7 @@ export const getMatchedColumns = <T extends string>(
) => ) =>
columns.reduce<Column<T>[]>((arr, column) => { columns.reduce<Column<T>[]>((arr, column) => {
const autoMatch = findMatch(column.header, fields, autoMapDistance); const autoMatch = findMatch(column.header, fields, autoMapDistance);
if (autoMatch) { if (isNonNullable(autoMatch)) {
const field = fields.find((field) => field.key === autoMatch) as Field<T>; const field = fields.find((field) => field.key === autoMatch) as Field<T>;
const duplicateIndex = arr.findIndex( const duplicateIndex = arr.findIndex(
(column) => 'value' in column && column.value === field.key, (column) => 'value' in column && column.value === field.key,

View File

@ -1,3 +1,5 @@
import { isNonEmptyString } from '@sniptt/guards';
const booleanWhitelist: Record<string, boolean> = { const booleanWhitelist: Record<string, boolean> = {
yes: true, yes: true,
no: false, no: false,
@ -6,7 +8,7 @@ const booleanWhitelist: Record<string, boolean> = {
}; };
export const normalizeCheckboxValue = (value: string | undefined): boolean => { export const normalizeCheckboxValue = (value: string | undefined): boolean => {
if (value && value.toLowerCase() in booleanWhitelist) { if (isNonEmptyString(value) && value.toLowerCase() in booleanWhitelist) {
return booleanWhitelist[value.toLowerCase()]; return booleanWhitelist[value.toLowerCase()];
} }
return false; return false;

View File

@ -24,7 +24,7 @@ export const normalizeTableData = <T extends string>(
if ( if (
'booleanMatches' in field.fieldType && 'booleanMatches' in field.fieldType &&
Object.keys(field.fieldType).length Object.keys(field.fieldType).length > 0
) { ) {
const booleanMatchKey = Object.keys( const booleanMatchKey = Object.keys(
field.fieldType.booleanMatches || [], field.fieldType.booleanMatches || [],

View File

@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState'; import { currentUserState } from '@/auth/states/currentUserState';
@ -9,6 +10,7 @@ import { IconHelpCircle } from '@/ui/display/icon';
import { Button } from '@/ui/input/button/components/Button'; import { Button } from '@/ui/input/button/components/Button';
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
import { User } from '~/generated/graphql'; import { User } from '~/generated/graphql';
import { isNonNullable } from '~/utils/isNonNullable';
const StyledButtonContainer = styled.div` const StyledButtonContainer = styled.div`
display: flex; display: flex;
@ -24,9 +26,9 @@ const insertScript = ({
onLoad?: (...args: any[]) => void; onLoad?: (...args: any[]) => void;
}) => { }) => {
const script = document.createElement('script'); const script = document.createElement('script');
if (src) script.src = src; if (isNonEmptyString(src)) script.src = src;
if (innerHTML) script.innerHTML = innerHTML; if (isNonEmptyString(innerHTML)) script.innerHTML = innerHTML;
if (onLoad) script.onload = onLoad; if (isNonNullable(onLoad)) script.onload = onLoad;
document.body.appendChild(script); document.body.appendChild(script);
}; };
@ -70,9 +72,9 @@ export const SupportChat = () => {
useEffect(() => { useEffect(() => {
if ( if (
supportChat?.supportDriver === 'front' && supportChat?.supportDriver === 'front' &&
supportChat.supportFrontChatId && isNonEmptyString(supportChat.supportFrontChatId) &&
currentUser?.email && isNonEmptyString(currentUser?.email) &&
currentWorkspaceMember && isNonNullable(currentWorkspaceMember) &&
!isFrontChatLoaded !isFrontChatLoaded
) { ) {
configureFront( configureFront(

Some files were not shown because too many files have changed in this diff Show More