Fix optimistic rendering (#2882)
* Release 0.2.1 * Optimistic rendering fixes * Fix optimistic rendering * Fix issues on Tasks * Fix Opportunity picker and relation picker
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "twenty",
|
"name": "twenty",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@air/react-drag-to-select": "^5.0.8",
|
"@air/react-drag-to-select": "^5.0.8",
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export const ActivityBodyEditor = ({
|
|||||||
const [body, setBody] = useState<string | null>(null);
|
const [body, setBody] = useState<string | null>(null);
|
||||||
const { updateOneRecord } = useUpdateOneRecord({
|
const { updateOneRecord } = useUpdateOneRecord({
|
||||||
objectNameSingular: 'activity',
|
objectNameSingular: 'activity',
|
||||||
|
refetchFindManyQuery: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -82,6 +82,7 @@ export const ActivityEditor = ({
|
|||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord<Activity>({
|
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord<Activity>({
|
||||||
objectNameSingular: 'activity',
|
objectNameSingular: 'activity',
|
||||||
|
refetchFindManyQuery: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { FieldContextProvider: DueAtFieldContextProvider } = useFieldContext({
|
const { FieldContextProvider: DueAtFieldContextProvider } = useFieldContext({
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export const useOpenCreateActivityDrawer = () => {
|
|||||||
});
|
});
|
||||||
const { createOneRecord: createOneActivity } = useCreateOneRecord<Activity>({
|
const { createOneRecord: createOneActivity } = useCreateOneRecord<Activity>({
|
||||||
objectNameSingular: 'activity',
|
objectNameSingular: 'activity',
|
||||||
|
refetchFindManyQuery: true,
|
||||||
});
|
});
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||||
const setHotkeyScope = useSetHotkeyScope();
|
const setHotkeyScope = useSetHotkeyScope();
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export const ActivityActionBar = ({ activityId }: ActivityActionBarProps) => {
|
|||||||
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||||
const { deleteOneRecord: deleteOneActivity } = useDeleteOneRecord({
|
const { deleteOneRecord: deleteOneActivity } = useDeleteOneRecord({
|
||||||
objectNameSingular: 'activity',
|
objectNameSingular: 'activity',
|
||||||
|
refetchFindManyQuery: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const deleteActivity = () => {
|
const deleteActivity = () => {
|
||||||
|
|||||||
@ -8,6 +8,7 @@ type Task = Pick<Activity, 'id' | 'completedAt'>;
|
|||||||
export const useCompleteTask = (task: Task) => {
|
export const useCompleteTask = (task: Task) => {
|
||||||
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord({
|
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord({
|
||||||
objectNameSingular: 'activity',
|
objectNameSingular: 'activity',
|
||||||
|
refetchFindManyQuery: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const completeTask = useCallback(
|
const completeTask = useCallback(
|
||||||
|
|||||||
@ -146,6 +146,7 @@ export const useOptimisticEffect = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[apolloClient.cache],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -7,12 +7,10 @@ import { BoardColumnContext } from '@/object-record/record-board/contexts/BoardC
|
|||||||
import { useCreateOpportunity } from '@/object-record/record-board/hooks/internal/useCreateOpportunity';
|
import { useCreateOpportunity } from '@/object-record/record-board/hooks/internal/useCreateOpportunity';
|
||||||
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
|
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
|
||||||
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
|
|
||||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
|
||||||
|
|
||||||
export const NewOpportunityButton = () => {
|
export const NewOpportunityButton = () => {
|
||||||
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
const [isCreatingCard, setIsCreatingCard] = useState(false);
|
||||||
@ -55,9 +53,7 @@ export const NewOpportunityButton = () => {
|
|||||||
setIsCreatingCard(false);
|
setIsCreatingCard(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [relationPickerSearchFilter] = useRecoilScopedState(
|
const { relationPickerSearchFilter } = useRelationPicker();
|
||||||
relationPickerSearchFilterScopedState,
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: refactor useFilteredSearchEntityQuery
|
// TODO: refactor useFilteredSearchEntityQuery
|
||||||
const { findManyRecordsQuery } = useObjectMetadataItem({
|
const { findManyRecordsQuery } = useObjectMetadataItem({
|
||||||
|
|||||||
@ -68,6 +68,13 @@ export const RecordShowPage = () => {
|
|||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const objectMetadataType =
|
||||||
|
objectMetadataItem?.nameSingular === 'company'
|
||||||
|
? 'Company'
|
||||||
|
: objectMetadataItem?.nameSingular === 'person'
|
||||||
|
? 'Person'
|
||||||
|
: 'Custom';
|
||||||
|
|
||||||
const useUpdateOneObjectRecordMutation: () => [
|
const useUpdateOneObjectRecordMutation: () => [
|
||||||
(params: any) => any,
|
(params: any) => any,
|
||||||
any,
|
any,
|
||||||
@ -171,22 +178,21 @@ export const RecordShowPage = () => {
|
|||||||
hasBackButton
|
hasBackButton
|
||||||
Icon={IconBuildingSkyscraper}
|
Icon={IconBuildingSkyscraper}
|
||||||
>
|
>
|
||||||
<PageFavoriteButton
|
{objectMetadataType !== 'Custom' && (
|
||||||
isFavorite={isFavorite}
|
<>
|
||||||
onClick={handleFavoriteButtonClick}
|
<PageFavoriteButton
|
||||||
/>
|
isFavorite={isFavorite}
|
||||||
<ShowPageAddButton
|
onClick={handleFavoriteButtonClick}
|
||||||
key="add"
|
/>
|
||||||
entity={{
|
<ShowPageAddButton
|
||||||
id: record.id,
|
key="add"
|
||||||
type:
|
entity={{
|
||||||
objectMetadataItem?.nameSingular === 'company'
|
id: record.id,
|
||||||
? 'Company'
|
type: objectMetadataType,
|
||||||
: objectMetadataItem?.nameSingular === 'person'
|
}}
|
||||||
? 'Person'
|
/>
|
||||||
: 'Custom',
|
</>
|
||||||
}}
|
)}
|
||||||
/>
|
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<PageBody>
|
<PageBody>
|
||||||
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
<RecoilScope CustomRecoilScopeContext={ShowPageRecoilScopeContext}>
|
||||||
|
|||||||
@ -1,24 +1,29 @@
|
|||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { v4 } from 'uuid';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
|
||||||
import { useGenerateEmptyRecord } from '@/object-record/hooks/useGenerateEmptyRecord';
|
import { useGenerateEmptyRecord } from '@/object-record/hooks/useGenerateEmptyRecord';
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
type useCreateOneRecordProps = {
|
||||||
|
objectNameSingular: string;
|
||||||
|
refetchFindManyQuery?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const useCreateOneRecord = <T>({
|
export const useCreateOneRecord = <T>({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: ObjectMetadataItemIdentifier) => {
|
refetchFindManyQuery = false,
|
||||||
|
}: useCreateOneRecordProps) => {
|
||||||
const { triggerOptimisticEffects } = useOptimisticEffect({
|
const { triggerOptimisticEffects } = useOptimisticEffect({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { objectMetadataItem, createOneRecordMutation } = useObjectMetadataItem(
|
const { objectMetadataItem, createOneRecordMutation, findManyRecordsQuery } =
|
||||||
{
|
useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: type this with a minimal type at least with Record<string, any>
|
// TODO: type this with a minimal type at least with Record<string, any>
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
@ -30,20 +35,30 @@ export const useCreateOneRecord = <T>({
|
|||||||
const createOneRecord = async (input: Record<string, any>) => {
|
const createOneRecord = async (input: Record<string, any>) => {
|
||||||
const recordId = v4();
|
const recordId = v4();
|
||||||
|
|
||||||
triggerOptimisticEffects(
|
const generatedEmptyRecord = generateEmptyRecord({
|
||||||
`${capitalize(objectMetadataItem.nameSingular)}Edge`,
|
id: recordId,
|
||||||
generateEmptyRecord(recordId),
|
...input,
|
||||||
);
|
});
|
||||||
|
|
||||||
|
if (generatedEmptyRecord) {
|
||||||
|
triggerOptimisticEffects(
|
||||||
|
`${capitalize(objectMetadataItem.nameSingular)}Edge`,
|
||||||
|
generatedEmptyRecord,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const createdObject = await apolloClient.mutate({
|
const createdObject = await apolloClient.mutate({
|
||||||
mutation: createOneRecordMutation,
|
mutation: createOneRecordMutation,
|
||||||
variables: {
|
variables: {
|
||||||
input: { ...input, id: recordId },
|
input: { id: recordId, ...input },
|
||||||
},
|
},
|
||||||
optimisticResponse: {
|
optimisticResponse: {
|
||||||
[`create${capitalize(objectMetadataItem.nameSingular)}`]:
|
[`create${capitalize(objectMetadataItem.nameSingular)}`]:
|
||||||
generateEmptyRecord(recordId),
|
generateEmptyRecord({ id: recordId, ...input }),
|
||||||
},
|
},
|
||||||
|
refetchQueries: refetchFindManyQuery
|
||||||
|
? [getOperationName(findManyRecordsQuery) ?? '']
|
||||||
|
: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!createdObject.data) {
|
if (!createdObject.data) {
|
||||||
|
|||||||
@ -1,25 +1,30 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
|
||||||
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
import { useOptimisticEffect } from '@/apollo/optimistic-effect/hooks/useOptimisticEffect';
|
||||||
import { useOptimisticEvict } from '@/apollo/optimistic-effect/hooks/useOptimisticEvict';
|
import { useOptimisticEvict } from '@/apollo/optimistic-effect/hooks/useOptimisticEvict';
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
type useDeleteOneRecordProps = {
|
||||||
|
objectNameSingular: string;
|
||||||
|
refetchFindManyQuery?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const useDeleteOneRecord = <T>({
|
export const useDeleteOneRecord = <T>({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: ObjectMetadataItemIdentifier) => {
|
refetchFindManyQuery = false,
|
||||||
|
}: useDeleteOneRecordProps) => {
|
||||||
const { performOptimisticEvict } = useOptimisticEvict();
|
const { performOptimisticEvict } = useOptimisticEvict();
|
||||||
const { triggerOptimisticEffects } = useOptimisticEffect({
|
const { triggerOptimisticEffects } = useOptimisticEffect({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { objectMetadataItem, deleteOneRecordMutation } = useObjectMetadataItem(
|
const { objectMetadataItem, deleteOneRecordMutation, findManyRecordsQuery } =
|
||||||
{
|
useObjectMetadataItem({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
@ -42,6 +47,9 @@ export const useDeleteOneRecord = <T>({
|
|||||||
variables: {
|
variables: {
|
||||||
idToDelete,
|
idToDelete,
|
||||||
},
|
},
|
||||||
|
refetchQueries: refetchFindManyQuery
|
||||||
|
? [getOperationName(findManyRecordsQuery) ?? '']
|
||||||
|
: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
return deletedRecord.data[
|
return deletedRecord.data[
|
||||||
@ -54,6 +62,8 @@ export const useDeleteOneRecord = <T>({
|
|||||||
performOptimisticEvict,
|
performOptimisticEvict,
|
||||||
apolloClient,
|
apolloClient,
|
||||||
deleteOneRecordMutation,
|
deleteOneRecordMutation,
|
||||||
|
refetchFindManyQuery,
|
||||||
|
findManyRecordsQuery,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -5,13 +5,17 @@ export const useGenerateEmptyRecord = ({
|
|||||||
}: {
|
}: {
|
||||||
objectMetadataItem: ObjectMetadataItem;
|
objectMetadataItem: ObjectMetadataItem;
|
||||||
}) => {
|
}) => {
|
||||||
const generateEmptyRecord = (id: string) => {
|
// Todo fix typing once we generate the return base on Metadata
|
||||||
|
const generateEmptyRecord = <T>(input: Partial<T> & { id: string }) => {
|
||||||
|
// Todo replace this by runtime typing
|
||||||
|
const validatedInput = input as { id: string } & { [key: string]: any };
|
||||||
|
|
||||||
if (objectMetadataItem.nameSingular === 'company') {
|
if (objectMetadataItem.nameSingular === 'company') {
|
||||||
return {
|
return {
|
||||||
id,
|
id: validatedInput.id,
|
||||||
domainName: '',
|
domainName: '',
|
||||||
accountOwnerId: null,
|
accountOwnerId: null,
|
||||||
createdAt: '2023-12-05T16:04:42.261Z',
|
createdAt: new Date().toISOString(),
|
||||||
address: '',
|
address: '',
|
||||||
people: [
|
people: [
|
||||||
{
|
{
|
||||||
@ -38,7 +42,7 @@ export const useGenerateEmptyRecord = ({
|
|||||||
currencyCode: null,
|
currencyCode: null,
|
||||||
__typename: 'Currency',
|
__typename: 'Currency',
|
||||||
},
|
},
|
||||||
updatedAt: '2023-12-05T16:04:42.261Z',
|
updatedAt: new Date().toISOString(),
|
||||||
employees: null,
|
employees: null,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
name: '',
|
name: '',
|
||||||
@ -56,12 +60,12 @@ export const useGenerateEmptyRecord = ({
|
|||||||
__typename: 'OpportunityConnection',
|
__typename: 'OpportunityConnection',
|
||||||
},
|
},
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
};
|
} as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectMetadataItem.nameSingular === 'person') {
|
if (objectMetadataItem.nameSingular === 'person') {
|
||||||
return {
|
return {
|
||||||
id,
|
id: validatedInput.id,
|
||||||
activityTargets: {
|
activityTargets: {
|
||||||
edges: [],
|
edges: [],
|
||||||
__typename: 'ActivityTargetConnection',
|
__typename: 'ActivityTargetConnection',
|
||||||
@ -98,8 +102,8 @@ export const useGenerateEmptyRecord = ({
|
|||||||
__typename: 'FullName',
|
__typename: 'FullName',
|
||||||
},
|
},
|
||||||
avatarUrl: '',
|
avatarUrl: '',
|
||||||
updatedAt: '2023-12-05T16:45:11.840Z',
|
updatedAt: new Date().toISOString(),
|
||||||
createdAt: '2023-12-05T16:45:11.840Z',
|
createdAt: new Date().toISOString(),
|
||||||
city: '',
|
city: '',
|
||||||
linkedinLink: {
|
linkedinLink: {
|
||||||
label: '',
|
label: '',
|
||||||
@ -107,25 +111,16 @@ export const useGenerateEmptyRecord = ({
|
|||||||
__typename: 'Link',
|
__typename: 'Link',
|
||||||
},
|
},
|
||||||
__typename: 'Person',
|
__typename: 'Person',
|
||||||
};
|
} as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectMetadataItem.nameSingular === 'opportunity') {
|
if (objectMetadataItem.nameSingular === 'opportunity') {
|
||||||
return {
|
return {
|
||||||
id,
|
id: validatedInput.id,
|
||||||
pipelineStepId: '30b14887-d592-427d-bd97-6e670158db02',
|
pipelineStepId: validatedInput.pipelineStepId,
|
||||||
closeDate: null,
|
closeDate: null,
|
||||||
companyId: '04b2e9f5-0713-40a5-8216-82802401d33e',
|
updatedAt: new Date().toISOString(),
|
||||||
updatedAt: '2023-12-05T16:46:27.621Z',
|
pipelineStep: null,
|
||||||
pipelineStep: {
|
|
||||||
id: '30b14887-d592-427d-bd97-6e670158db02',
|
|
||||||
position: 2,
|
|
||||||
name: 'Meeting',
|
|
||||||
updatedAt: '2023-12-05T11:29:21.485Z',
|
|
||||||
createdAt: '2023-12-05T11:29:21.485Z',
|
|
||||||
color: 'sky',
|
|
||||||
__typename: 'PipelineStep',
|
|
||||||
},
|
|
||||||
probability: '0',
|
probability: '0',
|
||||||
pointOfContactId: null,
|
pointOfContactId: null,
|
||||||
personId: null,
|
personId: null,
|
||||||
@ -134,41 +129,38 @@ export const useGenerateEmptyRecord = ({
|
|||||||
currencyCode: null,
|
currencyCode: null,
|
||||||
__typename: 'Currency',
|
__typename: 'Currency',
|
||||||
},
|
},
|
||||||
createdAt: '2023-12-05T16:46:27.621Z',
|
createdAt: new Date().toISOString(),
|
||||||
pointOfContact: null,
|
pointOfContact: null,
|
||||||
person: null,
|
person: null,
|
||||||
company: {
|
company: null,
|
||||||
id: '04b2e9f5-0713-40a5-8216-82802401d33e',
|
companyId: validatedInput.companyId,
|
||||||
domainName: 'qonto.com',
|
|
||||||
accountOwnerId: null,
|
|
||||||
createdAt: '2023-12-05T11:29:21.484Z',
|
|
||||||
address: '',
|
|
||||||
xLink: {
|
|
||||||
label: '',
|
|
||||||
url: '',
|
|
||||||
__typename: 'Link',
|
|
||||||
},
|
|
||||||
idealCustomerProfile: null,
|
|
||||||
annualRecurringRevenue: {
|
|
||||||
amountMicros: null,
|
|
||||||
currencyCode: null,
|
|
||||||
__typename: 'Currency',
|
|
||||||
},
|
|
||||||
updatedAt: '2023-12-05T11:29:21.484Z',
|
|
||||||
employees: null,
|
|
||||||
name: 'Qonto',
|
|
||||||
linkedinLink: {
|
|
||||||
label: '',
|
|
||||||
url: '',
|
|
||||||
__typename: 'Link',
|
|
||||||
},
|
|
||||||
__typename: 'Company',
|
|
||||||
},
|
|
||||||
__typename: 'Opportunity',
|
__typename: 'Opportunity',
|
||||||
};
|
} as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
if (objectMetadataItem.nameSingular === 'opportunity') {
|
||||||
|
return {
|
||||||
|
id: validatedInput.id,
|
||||||
|
pipelineStepId: validatedInput.pipelineStepId,
|
||||||
|
closeDate: null,
|
||||||
|
updatedAt: new Date().toISOString(),
|
||||||
|
pipelineStep: null,
|
||||||
|
probability: '0',
|
||||||
|
pointOfContactId: null,
|
||||||
|
personId: null,
|
||||||
|
amount: {
|
||||||
|
amountMicros: null,
|
||||||
|
currencyCode: null,
|
||||||
|
__typename: 'Currency',
|
||||||
|
},
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
pointOfContact: null,
|
||||||
|
person: null,
|
||||||
|
company: null,
|
||||||
|
companyId: validatedInput.companyId,
|
||||||
|
__typename: 'Opportunity',
|
||||||
|
} as T;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,16 +1,26 @@
|
|||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
|
||||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { ObjectMetadataItemIdentifier } from '@/object-metadata/types/ObjectMetadataItemIdentifier';
|
|
||||||
import { capitalize } from '~/utils/string/capitalize';
|
import { capitalize } from '~/utils/string/capitalize';
|
||||||
|
|
||||||
|
type useUpdateOneRecordProps = {
|
||||||
|
objectNameSingular: string;
|
||||||
|
refetchFindManyQuery?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const useUpdateOneRecord = <T>({
|
export const useUpdateOneRecord = <T>({
|
||||||
objectNameSingular,
|
objectNameSingular,
|
||||||
}: ObjectMetadataItemIdentifier) => {
|
refetchFindManyQuery = false,
|
||||||
const { objectMetadataItem, updateOneRecordMutation, getRecordFromCache } =
|
}: useUpdateOneRecordProps) => {
|
||||||
useObjectMetadataItem({
|
const {
|
||||||
objectNameSingular,
|
objectMetadataItem,
|
||||||
});
|
updateOneRecordMutation,
|
||||||
|
getRecordFromCache,
|
||||||
|
findManyRecordsQuery,
|
||||||
|
} = useObjectMetadataItem({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
const apolloClient = useApolloClient();
|
const apolloClient = useApolloClient();
|
||||||
|
|
||||||
@ -38,6 +48,9 @@ export const useUpdateOneRecord = <T>({
|
|||||||
...input,
|
...input,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
refetchQueries: refetchFindManyQuery
|
||||||
|
? [getOperationName(findManyRecordsQuery) ?? '']
|
||||||
|
: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!updatedRecord?.data) {
|
if (!updatedRecord?.data) {
|
||||||
|
|||||||
@ -7,11 +7,9 @@ import { FieldDefinition } from '@/object-record/field/types/FieldDefinition';
|
|||||||
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
import { FieldRelationMetadata } from '@/object-record/field/types/FieldMetadata';
|
||||||
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
|
import { SingleEntitySelect } from '@/object-record/relation-picker/components/SingleEntitySelect';
|
||||||
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
|
|
||||||
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
import { EntityForSelect } from '@/object-record/relation-picker/types/EntityForSelect';
|
||||||
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
|
||||||
import { IconForbid } from '@/ui/display/icon';
|
import { IconForbid } from '@/ui/display/icon';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
|
||||||
|
|
||||||
export type RelationPickerProps = {
|
export type RelationPickerProps = {
|
||||||
recordId?: string;
|
recordId?: string;
|
||||||
@ -32,8 +30,8 @@ export const RelationPicker = ({
|
|||||||
initialSearchFilter,
|
initialSearchFilter,
|
||||||
fieldDefinition,
|
fieldDefinition,
|
||||||
}: RelationPickerProps) => {
|
}: RelationPickerProps) => {
|
||||||
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
const { relationPickerSearchFilter, setRelationPickerSearchFilter } =
|
||||||
useRecoilScopedState(relationPickerSearchFilterScopedState);
|
useRelationPicker();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
setRelationPickerSearchFilter(initialSearchFilter ?? '');
|
||||||
|
|||||||
@ -2,14 +2,13 @@ import { expect } from '@storybook/jest';
|
|||||||
import { Meta, StoryObj } from '@storybook/react';
|
import { Meta, StoryObj } from '@storybook/react';
|
||||||
import { userEvent, within } from '@storybook/testing-library';
|
import { userEvent, within } from '@storybook/testing-library';
|
||||||
|
|
||||||
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { IconUserCircle } from '@/ui/display/icon';
|
import { IconUserCircle } from '@/ui/display/icon';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
import { ComponentWithRecoilScopeDecorator } from '~/testing/decorators/ComponentWithRecoilScopeDecorator';
|
||||||
import { mockedPeopleData } from '~/testing/mock-data/people';
|
import { mockedPeopleData } from '~/testing/mock-data/people';
|
||||||
import { sleep } from '~/testing/sleep';
|
import { sleep } from '~/testing/sleep';
|
||||||
|
|
||||||
import { relationPickerSearchFilterScopedState } from '../../states/relationPickerSearchFilterScopedState';
|
|
||||||
import { EntityForSelect } from '../../types/EntityForSelect';
|
import { EntityForSelect } from '../../types/EntityForSelect';
|
||||||
import { SingleEntitySelect } from '../SingleEntitySelect';
|
import { SingleEntitySelect } from '../SingleEntitySelect';
|
||||||
|
|
||||||
@ -44,9 +43,7 @@ const meta: Meta<typeof SingleEntitySelect> = {
|
|||||||
width,
|
width,
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const relationPickerSearchFilter = useRecoilScopedValue(
|
const { relationPickerSearchFilter } = useRelationPicker();
|
||||||
relationPickerSearchFilterScopedState,
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SingleEntitySelect
|
<SingleEntitySelect
|
||||||
|
|||||||
@ -12,17 +12,20 @@ export const useRelationPickerScopedStates = (args?: {
|
|||||||
relationPickerScopedId,
|
relationPickerScopedId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { identifiersMapperState } = getRelationPickerScopedStates({
|
const {
|
||||||
relationPickerScopeId: scopeId,
|
identifiersMapperState,
|
||||||
});
|
relationPickerSearchFilterState,
|
||||||
|
relationPickerPreselectedIdState,
|
||||||
const { searchQueryState } = getRelationPickerScopedStates({
|
searchQueryState,
|
||||||
|
} = getRelationPickerScopedStates({
|
||||||
relationPickerScopeId: scopeId,
|
relationPickerScopeId: scopeId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scopeId,
|
scopeId,
|
||||||
identifiersMapperState,
|
identifiersMapperState,
|
||||||
|
relationPickerSearchFilterState,
|
||||||
|
relationPickerPreselectedIdState,
|
||||||
searchQueryState,
|
searchQueryState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import scrollIntoView from 'scroll-into-view';
|
import scrollIntoView from 'scroll-into-view';
|
||||||
import { Key } from 'ts-key-enum';
|
import { Key } from 'ts-key-enum';
|
||||||
|
|
||||||
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
|
||||||
|
|
||||||
import { CreateButtonId } from '../constants';
|
import { CreateButtonId } from '../constants';
|
||||||
import { RelationPickerRecoilScopeContext } from '../states/recoil-scope-contexts/RelationPickerRecoilScopeContext';
|
|
||||||
import { relationPickerPreselectedIdScopedState } from '../states/relationPickerPreselectedIdScopedState';
|
|
||||||
import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope';
|
import { RelationPickerHotkeyScope } from '../types/RelationPickerHotkeyScope';
|
||||||
import { getPreselectedIdIndex } from '../utils/getPreselectedIdIndex';
|
import { getPreselectedIdIndex } from '../utils/getPreselectedIdIndex';
|
||||||
|
|
||||||
@ -17,15 +15,12 @@ export const useEntitySelectScroll = ({
|
|||||||
selectableOptionIds: string[];
|
selectableOptionIds: string[];
|
||||||
containerRef: React.RefObject<HTMLDivElement>;
|
containerRef: React.RefObject<HTMLDivElement>;
|
||||||
}) => {
|
}) => {
|
||||||
const [relationPickerPreselectedId, setRelationPickerPreselectedId] =
|
const { relationPickerPreselectedId, setRelationPickerPreselectedId } =
|
||||||
useRecoilScopedState(
|
useRelationPicker();
|
||||||
relationPickerPreselectedIdScopedState,
|
|
||||||
RelationPickerRecoilScopeContext,
|
|
||||||
);
|
|
||||||
|
|
||||||
const preselectedIdIndex = getPreselectedIdIndex(
|
const preselectedIdIndex = getPreselectedIdIndex(
|
||||||
selectableOptionIds,
|
selectableOptionIds,
|
||||||
relationPickerPreselectedId,
|
relationPickerPreselectedId ?? '',
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetScroll = () => {
|
const resetScroll = () => {
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
|
||||||
import { relationPickerPreselectedIdScopedState } from '@/object-record/relation-picker/states/relationPickerPreselectedIdScopedState';
|
import { useRelationPicker } from '@/object-record/relation-picker/hooks/useRelationPicker';
|
||||||
import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
|
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
|
||||||
|
|
||||||
export const useEntitySelectSearch = () => {
|
export const useEntitySelectSearch = () => {
|
||||||
const [, setRelationPickerPreselectedId] = useRecoilScopedState(
|
const {
|
||||||
relationPickerPreselectedIdScopedState,
|
setRelationPickerPreselectedId,
|
||||||
);
|
relationPickerSearchFilter,
|
||||||
|
setRelationPickerSearchFilter,
|
||||||
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
} = useRelationPicker();
|
||||||
useRecoilScopedState(relationPickerSearchFilterScopedState);
|
|
||||||
|
|
||||||
const debouncedSetSearchFilter = debounce(
|
const debouncedSetSearchFilter = debounce(
|
||||||
setRelationPickerSearchFilter,
|
setRelationPickerSearchFilter,
|
||||||
|
|||||||
@ -14,10 +14,14 @@ export const useRelationPicker = (props?: useRelationPickeProps) => {
|
|||||||
props?.relationPickerScopeId,
|
props?.relationPickerScopeId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { identifiersMapperState, searchQueryState } =
|
const {
|
||||||
useRelationPickerScopedStates({
|
identifiersMapperState,
|
||||||
relationPickerScopedId: scopeId,
|
searchQueryState,
|
||||||
});
|
relationPickerSearchFilterState,
|
||||||
|
relationPickerPreselectedIdState,
|
||||||
|
} = useRelationPickerScopedStates({
|
||||||
|
relationPickerScopedId: scopeId,
|
||||||
|
});
|
||||||
|
|
||||||
const [identifiersMapper, setIdentifiersMapper] = useRecoilState(
|
const [identifiersMapper, setIdentifiersMapper] = useRecoilState(
|
||||||
identifiersMapperState,
|
identifiersMapperState,
|
||||||
@ -25,11 +29,21 @@ export const useRelationPicker = (props?: useRelationPickeProps) => {
|
|||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useRecoilState(searchQueryState);
|
const [searchQuery, setSearchQuery] = useRecoilState(searchQueryState);
|
||||||
|
|
||||||
|
const [relationPickerSearchFilter, setRelationPickerSearchFilter] =
|
||||||
|
useRecoilState(relationPickerSearchFilterState);
|
||||||
|
|
||||||
|
const [relationPickerPreselectedId, setRelationPickerPreselectedId] =
|
||||||
|
useRecoilState(relationPickerPreselectedIdState);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
scopeId,
|
scopeId,
|
||||||
identifiersMapper,
|
identifiersMapper,
|
||||||
setIdentifiersMapper,
|
setIdentifiersMapper,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
setSearchQuery,
|
setSearchQuery,
|
||||||
|
relationPickerSearchFilter,
|
||||||
|
setRelationPickerSearchFilter,
|
||||||
|
relationPickerPreselectedId,
|
||||||
|
setRelationPickerPreselectedId,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { atomFamily } from 'recoil';
|
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||||
|
|
||||||
export const relationPickerPreselectedIdScopedState = atomFamily<
|
export const relationPickerPreselectedIdScopedState = createScopedState<
|
||||||
string,
|
string | undefined
|
||||||
string
|
|
||||||
>({
|
>({
|
||||||
key: 'relationPickerPreselectedIdScopedState',
|
key: 'relationPickerPreselectedIdScopedState',
|
||||||
default: (param) => param,
|
defaultValue: undefined,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import { atomFamily } from 'recoil';
|
import { createScopedState } from '@/ui/utilities/recoil-scope/utils/createScopedState';
|
||||||
|
|
||||||
export const relationPickerSearchFilterScopedState = atomFamily<string, string>(
|
export const relationPickerSearchFilterScopedState = createScopedState<string>({
|
||||||
{
|
key: 'relationPickerSearchFilterScopedState',
|
||||||
key: 'relationPickerSearchFilterScopedState',
|
defaultValue: '',
|
||||||
default: '',
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { identifiersMapperScopedState } from '@/object-record/relation-picker/states/identifiersMapperScopedState';
|
import { identifiersMapperScopedState } from '@/object-record/relation-picker/states/identifiersMapperScopedState';
|
||||||
|
import { relationPickerPreselectedIdScopedState } from '@/object-record/relation-picker/states/relationPickerPreselectedIdScopedState';
|
||||||
|
import { relationPickerSearchFilterScopedState } from '@/object-record/relation-picker/states/relationPickerSearchFilterScopedState';
|
||||||
import { searchQueryScopedState } from '@/object-record/relation-picker/states/searchQueryScopedState';
|
import { searchQueryScopedState } from '@/object-record/relation-picker/states/searchQueryScopedState';
|
||||||
import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState';
|
import { getScopedState } from '@/ui/utilities/recoil-scope/utils/getScopedState';
|
||||||
|
|
||||||
@ -17,8 +19,20 @@ export const getRelationPickerScopedStates = ({
|
|||||||
relationPickerScopeId,
|
relationPickerScopeId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const relationPickerPreselectedIdState = getScopedState(
|
||||||
|
relationPickerPreselectedIdScopedState,
|
||||||
|
relationPickerScopeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const relationPickerSearchFilterState = getScopedState(
|
||||||
|
relationPickerSearchFilterScopedState,
|
||||||
|
relationPickerScopeId,
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
identifiersMapperState,
|
identifiersMapperState,
|
||||||
|
relationPickerSearchFilterState,
|
||||||
|
relationPickerPreselectedIdState,
|
||||||
searchQueryState,
|
searchQueryState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
const StyledSection = styled.div`
|
const StyledSection = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${({ theme }) => theme.betweenSiblingsGap};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export { StyledSection as NavigationDrawerSection };
|
export { StyledSection as NavigationDrawerSection };
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||||||
|
|
||||||
import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCreateOneRelationMetadataItem';
|
import { useCreateOneRelationMetadataItem } from '@/object-metadata/hooks/useCreateOneRelationMetadataItem';
|
||||||
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem';
|
||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
|
||||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||||
import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults';
|
import { PaginatedRecordTypeResults } from '@/object-record/types/PaginatedRecordTypeResults';
|
||||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||||
@ -74,8 +74,8 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
const [objectViews, setObjectViews] = useState<View[]>([]);
|
const [objectViews, setObjectViews] = useState<View[]>([]);
|
||||||
const [relationObjectViews, setRelationObjectViews] = useState<View[]>([]);
|
const [relationObjectViews, setRelationObjectViews] = useState<View[]>([]);
|
||||||
|
|
||||||
const { createOneRecord: createOneViewField } = useCreateOneRecord({
|
const { modifyRecordFromCache: modifyViewFromCache } = useObjectMetadataItem({
|
||||||
objectNameSingular: 'viewField',
|
objectNameSingular: 'view',
|
||||||
});
|
});
|
||||||
|
|
||||||
useFindManyRecords({
|
useFindManyRecords({
|
||||||
@ -141,7 +141,7 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
objectViews.forEach(async (view) => {
|
objectViews.forEach(async (view) => {
|
||||||
await createOneViewField?.({
|
const viewFieldToCreate = {
|
||||||
viewId: view.id,
|
viewId: view.id,
|
||||||
fieldMetadataId:
|
fieldMetadataId:
|
||||||
validatedFormValues.relation.type === 'MANY_TO_ONE'
|
validatedFormValues.relation.type === 'MANY_TO_ONE'
|
||||||
@ -150,10 +150,25 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
position: activeObjectMetadataItem.fields.length,
|
position: activeObjectMetadataItem.fields.length,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
size: 100,
|
size: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
modifyViewFromCache(view.id, {
|
||||||
|
// Todo fix typing
|
||||||
|
viewFields: (viewFields: any) => {
|
||||||
|
return {
|
||||||
|
edges: viewFields.edges.concat({ node: viewFieldToCreate }),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
relationObjectViews.forEach(async (view) => {
|
relationObjectViews.forEach(async (view) => {
|
||||||
await createOneViewField?.({
|
const viewFieldToCreate = {
|
||||||
viewId: view.id,
|
viewId: view.id,
|
||||||
fieldMetadataId:
|
fieldMetadataId:
|
||||||
validatedFormValues.relation.type === 'MANY_TO_ONE'
|
validatedFormValues.relation.type === 'MANY_TO_ONE'
|
||||||
@ -162,10 +177,24 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
position: relationObjectMetadataItem?.fields.length,
|
position: relationObjectMetadataItem?.fields.length,
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
size: 100,
|
size: 100,
|
||||||
|
};
|
||||||
|
modifyViewFromCache(view.id, {
|
||||||
|
// Todo fix typing
|
||||||
|
viewFields: (viewFields: any) => {
|
||||||
|
return {
|
||||||
|
edges: viewFields.edges.concat({ node: viewFieldToCreate }),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await createMetadataField({
|
const createdMetadataField = await createMetadataField({
|
||||||
description: validatedFormValues.description,
|
description: validatedFormValues.description,
|
||||||
icon: validatedFormValues.icon,
|
icon: validatedFormValues.icon,
|
||||||
label: validatedFormValues.label ?? '',
|
label: validatedFormValues.label ?? '',
|
||||||
@ -176,6 +205,31 @@ export const SettingsObjectNewFieldStep2 = () => {
|
|||||||
? validatedFormValues.select
|
? validatedFormValues.select
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
objectViews.forEach(async (view) => {
|
||||||
|
const viewFieldToCreate = {
|
||||||
|
viewId: view.id,
|
||||||
|
fieldMetadataId: createdMetadataField.data?.createOneField.id,
|
||||||
|
position: activeObjectMetadataItem.fields.length,
|
||||||
|
isVisible: true,
|
||||||
|
size: 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
modifyViewFromCache(view.id, {
|
||||||
|
// Todo fix typing
|
||||||
|
viewFields: (viewFields: any) => {
|
||||||
|
return {
|
||||||
|
edges: viewFields.edges.concat({ node: viewFieldToCreate }),
|
||||||
|
pageInfo: {
|
||||||
|
hasNextPage: false,
|
||||||
|
hasPreviousPage: false,
|
||||||
|
startCursor: '',
|
||||||
|
endCursor: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`/settings/objects/${objectSlug}`);
|
navigate(`/settings/objects/${objectSlug}`);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "",
|
"author": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@ -131,6 +131,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
isNullable: true,
|
isNullable: true,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
isCustom: false,
|
isCustom: false,
|
||||||
|
isSystem: true,
|
||||||
workspaceId: record.workspaceId,
|
workspaceId: record.workspaceId,
|
||||||
defaultValue: { type: 'now' },
|
defaultValue: { type: 'now' },
|
||||||
},
|
},
|
||||||
@ -168,7 +169,9 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
|||||||
type: FieldMetadataType.RELATION,
|
type: FieldMetadataType.RELATION,
|
||||||
name: record.nameSingular,
|
name: record.nameSingular,
|
||||||
label: record.labelSingular,
|
label: record.labelSingular,
|
||||||
targetColumnMap: {},
|
targetColumnMap: {
|
||||||
|
value: `${createdObjectMetadata.targetTableName}Id`,
|
||||||
|
},
|
||||||
description: `ActivityTarget ${record.labelSingular}`,
|
description: `ActivityTarget ${record.labelSingular}`,
|
||||||
icon: 'IconBuildingSkyscraper',
|
icon: 'IconBuildingSkyscraper',
|
||||||
isNullable: true,
|
isNullable: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user