mirror of
https://github.com/twentyhq/twenty.git
synced 2024-11-22 11:43:34 +03:00
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:
parent
40bea0d95e
commit
17511be0cf
@ -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",
|
||||||
|
@ -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: {},
|
||||||
},
|
},
|
||||||
|
@ -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",
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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>
|
||||||
|
@ -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(),
|
||||||
|
@ -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'
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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',
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = () => {
|
||||||
|
@ -49,7 +49,7 @@ export const useOpenCreateActivityDrawerForSelectedRowIds = (
|
|||||||
})
|
})
|
||||||
.filter(isNonNullable);
|
.filter(isNonNullable);
|
||||||
|
|
||||||
if (relatedEntities) {
|
if (isNonNullable(relatedEntities)) {
|
||||||
activityTargetableObjectArray =
|
activityTargetableObjectArray =
|
||||||
activityTargetableObjectArray.concat(relatedEntities);
|
activityTargetableObjectArray.concat(relatedEntities);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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({
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]);
|
||||||
|
@ -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) {
|
||||||
|
@ -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) =>
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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',
|
||||||
});
|
});
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
@ -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`,
|
||||||
);
|
);
|
||||||
|
@ -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?.();
|
||||||
|
@ -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,
|
||||||
|
@ -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) ||
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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']: {
|
||||||
|
@ -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);
|
||||||
|
@ -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],
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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(
|
||||||
|
@ -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}%`,
|
||||||
|
@ -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]: {
|
||||||
|
@ -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})`] || '',
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]: {
|
||||||
|
@ -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 />;
|
||||||
|
|
||||||
|
@ -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 />;
|
||||||
|
@ -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 />;
|
||||||
|
@ -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 />;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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';
|
||||||
|
@ -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',
|
||||||
});
|
});
|
||||||
|
@ -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');
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
||||||
|
@ -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}
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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 || [],
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user