feat: disallow removing all comment thread targets (#779)
* feat: disallow removing all comment thread targets Closes #431 * Rename variables * Fix console error --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1915,24 +1915,21 @@ export type GetCommentThreadQueryVariables = Exact<{
|
|||||||
|
|
||||||
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, body?: string | null, title?: string | null, type: ActivityType, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
|
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, body?: string | null, title?: string | null, type: ActivityType, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null, displayName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
|
||||||
|
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationVariables = Exact<{
|
export type AddCommentThreadTargetsOnCommentThreadMutationVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
commentThreadTargetCreationDate: Scalars['DateTime'];
|
commentThreadTargetInputs: Array<CommentThreadTargetCreateManyCommentThreadInput> | CommentThreadTargetCreateManyCommentThreadInput;
|
||||||
commentThreadTargetId: Scalars['String'];
|
|
||||||
commentableEntityId: Scalars['String'];
|
|
||||||
commentableEntityType: CommentableType;
|
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentableType: CommentableType, commentableId: string }> | null } };
|
export type AddCommentThreadTargetsOnCommentThreadMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentableType: CommentableType, commentableId: string }> | null } };
|
||||||
|
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutationVariables = Exact<{
|
export type RemoveCommentThreadTargetsOnCommentThreadMutationVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
commentThreadTargetId: Scalars['String'];
|
commentThreadTargetIds: Array<Scalars['String']> | Scalars['String'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentableType: CommentableType, commentableId: string }> | null } };
|
export type RemoveCommentThreadTargetsOnCommentThreadMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentableType: CommentableType, commentableId: string }> | null } };
|
||||||
|
|
||||||
export type DeleteCommentThreadMutationVariables = Exact<{
|
export type DeleteCommentThreadMutationVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
@ -2531,11 +2528,11 @@ export function useGetCommentThreadLazyQuery(baseOptions?: Apollo.LazyQueryHookO
|
|||||||
export type GetCommentThreadQueryHookResult = ReturnType<typeof useGetCommentThreadQuery>;
|
export type GetCommentThreadQueryHookResult = ReturnType<typeof useGetCommentThreadQuery>;
|
||||||
export type GetCommentThreadLazyQueryHookResult = ReturnType<typeof useGetCommentThreadLazyQuery>;
|
export type GetCommentThreadLazyQueryHookResult = ReturnType<typeof useGetCommentThreadLazyQuery>;
|
||||||
export type GetCommentThreadQueryResult = Apollo.QueryResult<GetCommentThreadQuery, GetCommentThreadQueryVariables>;
|
export type GetCommentThreadQueryResult = Apollo.QueryResult<GetCommentThreadQuery, GetCommentThreadQueryVariables>;
|
||||||
export const AddCommentThreadTargetOnCommentThreadDocument = gql`
|
export const AddCommentThreadTargetsOnCommentThreadDocument = gql`
|
||||||
mutation AddCommentThreadTargetOnCommentThread($commentThreadId: String!, $commentThreadTargetCreationDate: DateTime!, $commentThreadTargetId: String!, $commentableEntityId: String!, $commentableEntityType: CommentableType!) {
|
mutation AddCommentThreadTargetsOnCommentThread($commentThreadId: String!, $commentThreadTargetInputs: [CommentThreadTargetCreateManyCommentThreadInput!]!) {
|
||||||
updateOneCommentThread(
|
updateOneCommentThread(
|
||||||
where: {id: $commentThreadId}
|
where: {id: $commentThreadId}
|
||||||
data: {commentThreadTargets: {connectOrCreate: {create: {id: $commentThreadTargetId, createdAt: $commentThreadTargetCreationDate, commentableType: $commentableEntityType, commentableId: $commentableEntityId}, where: {id: $commentThreadTargetId}}}}
|
data: {commentThreadTargets: {createMany: {data: $commentThreadTargetInputs}}}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
@ -2550,41 +2547,38 @@ export const AddCommentThreadTargetOnCommentThreadDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationFn = Apollo.MutationFunction<AddCommentThreadTargetOnCommentThreadMutation, AddCommentThreadTargetOnCommentThreadMutationVariables>;
|
export type AddCommentThreadTargetsOnCommentThreadMutationFn = Apollo.MutationFunction<AddCommentThreadTargetsOnCommentThreadMutation, AddCommentThreadTargetsOnCommentThreadMutationVariables>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useAddCommentThreadTargetOnCommentThreadMutation__
|
* __useAddCommentThreadTargetsOnCommentThreadMutation__
|
||||||
*
|
*
|
||||||
* To run a mutation, you first call `useAddCommentThreadTargetOnCommentThreadMutation` within a React component and pass it any options that fit your needs.
|
* To run a mutation, you first call `useAddCommentThreadTargetsOnCommentThreadMutation` within a React component and pass it any options that fit your needs.
|
||||||
* When your component renders, `useAddCommentThreadTargetOnCommentThreadMutation` returns a tuple that includes:
|
* When your component renders, `useAddCommentThreadTargetsOnCommentThreadMutation` returns a tuple that includes:
|
||||||
* - A mutate function that you can call at any time to execute the mutation
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
* - An object with fields that represent the current status of the mutation's execution
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
*
|
*
|
||||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const [addCommentThreadTargetOnCommentThreadMutation, { data, loading, error }] = useAddCommentThreadTargetOnCommentThreadMutation({
|
* const [addCommentThreadTargetsOnCommentThreadMutation, { data, loading, error }] = useAddCommentThreadTargetsOnCommentThreadMutation({
|
||||||
* variables: {
|
* variables: {
|
||||||
* commentThreadId: // value for 'commentThreadId'
|
* commentThreadId: // value for 'commentThreadId'
|
||||||
* commentThreadTargetCreationDate: // value for 'commentThreadTargetCreationDate'
|
* commentThreadTargetInputs: // value for 'commentThreadTargetInputs'
|
||||||
* commentThreadTargetId: // value for 'commentThreadTargetId'
|
|
||||||
* commentableEntityId: // value for 'commentableEntityId'
|
|
||||||
* commentableEntityType: // value for 'commentableEntityType'
|
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function useAddCommentThreadTargetOnCommentThreadMutation(baseOptions?: Apollo.MutationHookOptions<AddCommentThreadTargetOnCommentThreadMutation, AddCommentThreadTargetOnCommentThreadMutationVariables>) {
|
export function useAddCommentThreadTargetsOnCommentThreadMutation(baseOptions?: Apollo.MutationHookOptions<AddCommentThreadTargetsOnCommentThreadMutation, AddCommentThreadTargetsOnCommentThreadMutationVariables>) {
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
return Apollo.useMutation<AddCommentThreadTargetOnCommentThreadMutation, AddCommentThreadTargetOnCommentThreadMutationVariables>(AddCommentThreadTargetOnCommentThreadDocument, options);
|
return Apollo.useMutation<AddCommentThreadTargetsOnCommentThreadMutation, AddCommentThreadTargetsOnCommentThreadMutationVariables>(AddCommentThreadTargetsOnCommentThreadDocument, options);
|
||||||
}
|
}
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationHookResult = ReturnType<typeof useAddCommentThreadTargetOnCommentThreadMutation>;
|
export type AddCommentThreadTargetsOnCommentThreadMutationHookResult = ReturnType<typeof useAddCommentThreadTargetsOnCommentThreadMutation>;
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationResult = Apollo.MutationResult<AddCommentThreadTargetOnCommentThreadMutation>;
|
export type AddCommentThreadTargetsOnCommentThreadMutationResult = Apollo.MutationResult<AddCommentThreadTargetsOnCommentThreadMutation>;
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationOptions = Apollo.BaseMutationOptions<AddCommentThreadTargetOnCommentThreadMutation, AddCommentThreadTargetOnCommentThreadMutationVariables>;
|
export type AddCommentThreadTargetsOnCommentThreadMutationOptions = Apollo.BaseMutationOptions<AddCommentThreadTargetsOnCommentThreadMutation, AddCommentThreadTargetsOnCommentThreadMutationVariables>;
|
||||||
export const RemoveCommentThreadTargetOnCommentThreadDocument = gql`
|
export const RemoveCommentThreadTargetsOnCommentThreadDocument = gql`
|
||||||
mutation RemoveCommentThreadTargetOnCommentThread($commentThreadId: String!, $commentThreadTargetId: String!) {
|
mutation RemoveCommentThreadTargetsOnCommentThread($commentThreadId: String!, $commentThreadTargetIds: [String!]!) {
|
||||||
updateOneCommentThread(
|
updateOneCommentThread(
|
||||||
where: {id: $commentThreadId}
|
where: {id: $commentThreadId}
|
||||||
data: {commentThreadTargets: {delete: {id: $commentThreadTargetId}}}
|
data: {commentThreadTargets: {deleteMany: {id: {in: $commentThreadTargetIds}}}}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
@ -2599,33 +2593,33 @@ export const RemoveCommentThreadTargetOnCommentThreadDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutationFn = Apollo.MutationFunction<RemoveCommentThreadTargetOnCommentThreadMutation, RemoveCommentThreadTargetOnCommentThreadMutationVariables>;
|
export type RemoveCommentThreadTargetsOnCommentThreadMutationFn = Apollo.MutationFunction<RemoveCommentThreadTargetsOnCommentThreadMutation, RemoveCommentThreadTargetsOnCommentThreadMutationVariables>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useRemoveCommentThreadTargetOnCommentThreadMutation__
|
* __useRemoveCommentThreadTargetsOnCommentThreadMutation__
|
||||||
*
|
*
|
||||||
* To run a mutation, you first call `useRemoveCommentThreadTargetOnCommentThreadMutation` within a React component and pass it any options that fit your needs.
|
* To run a mutation, you first call `useRemoveCommentThreadTargetsOnCommentThreadMutation` within a React component and pass it any options that fit your needs.
|
||||||
* When your component renders, `useRemoveCommentThreadTargetOnCommentThreadMutation` returns a tuple that includes:
|
* When your component renders, `useRemoveCommentThreadTargetsOnCommentThreadMutation` returns a tuple that includes:
|
||||||
* - A mutate function that you can call at any time to execute the mutation
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
* - An object with fields that represent the current status of the mutation's execution
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
*
|
*
|
||||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const [removeCommentThreadTargetOnCommentThreadMutation, { data, loading, error }] = useRemoveCommentThreadTargetOnCommentThreadMutation({
|
* const [removeCommentThreadTargetsOnCommentThreadMutation, { data, loading, error }] = useRemoveCommentThreadTargetsOnCommentThreadMutation({
|
||||||
* variables: {
|
* variables: {
|
||||||
* commentThreadId: // value for 'commentThreadId'
|
* commentThreadId: // value for 'commentThreadId'
|
||||||
* commentThreadTargetId: // value for 'commentThreadTargetId'
|
* commentThreadTargetIds: // value for 'commentThreadTargetIds'
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function useRemoveCommentThreadTargetOnCommentThreadMutation(baseOptions?: Apollo.MutationHookOptions<RemoveCommentThreadTargetOnCommentThreadMutation, RemoveCommentThreadTargetOnCommentThreadMutationVariables>) {
|
export function useRemoveCommentThreadTargetsOnCommentThreadMutation(baseOptions?: Apollo.MutationHookOptions<RemoveCommentThreadTargetsOnCommentThreadMutation, RemoveCommentThreadTargetsOnCommentThreadMutationVariables>) {
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
return Apollo.useMutation<RemoveCommentThreadTargetOnCommentThreadMutation, RemoveCommentThreadTargetOnCommentThreadMutationVariables>(RemoveCommentThreadTargetOnCommentThreadDocument, options);
|
return Apollo.useMutation<RemoveCommentThreadTargetsOnCommentThreadMutation, RemoveCommentThreadTargetsOnCommentThreadMutationVariables>(RemoveCommentThreadTargetsOnCommentThreadDocument, options);
|
||||||
}
|
}
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutationHookResult = ReturnType<typeof useRemoveCommentThreadTargetOnCommentThreadMutation>;
|
export type RemoveCommentThreadTargetsOnCommentThreadMutationHookResult = ReturnType<typeof useRemoveCommentThreadTargetsOnCommentThreadMutation>;
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutationResult = Apollo.MutationResult<RemoveCommentThreadTargetOnCommentThreadMutation>;
|
export type RemoveCommentThreadTargetsOnCommentThreadMutationResult = Apollo.MutationResult<RemoveCommentThreadTargetsOnCommentThreadMutation>;
|
||||||
export type RemoveCommentThreadTargetOnCommentThreadMutationOptions = Apollo.BaseMutationOptions<RemoveCommentThreadTargetOnCommentThreadMutation, RemoveCommentThreadTargetOnCommentThreadMutationVariables>;
|
export type RemoveCommentThreadTargetsOnCommentThreadMutationOptions = Apollo.BaseMutationOptions<RemoveCommentThreadTargetsOnCommentThreadMutation, RemoveCommentThreadTargetsOnCommentThreadMutationVariables>;
|
||||||
export const DeleteCommentThreadDocument = gql`
|
export const DeleteCommentThreadDocument = gql`
|
||||||
mutation DeleteCommentThread($commentThreadId: String!) {
|
mutation DeleteCommentThread($commentThreadId: String!) {
|
||||||
deleteManyCommentThreads(where: {id: {equals: $commentThreadId}}) {
|
deleteManyCommentThreads(where: {id: {equals: $commentThreadId}}) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import {
|
import {
|
||||||
autoUpdate,
|
autoUpdate,
|
||||||
@ -78,56 +78,98 @@ const StyledMenuWrapper = styled.div`
|
|||||||
export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [searchFilter, setSearchFilter] = useState('');
|
const [searchFilter, setSearchFilter] = useState('');
|
||||||
|
const [selectedEntityIds, setSelectedEntityIds] = useState<
|
||||||
const peopleIds =
|
Record<string, boolean>
|
||||||
commentThread?.commentThreadTargets
|
>({});
|
||||||
?.filter((relation) => relation.commentableType === 'Person')
|
|
||||||
.map((relation) => relation.commentableId) ?? [];
|
|
||||||
const companyIds =
|
|
||||||
commentThread?.commentThreadTargets
|
|
||||||
?.filter((relation) => relation.commentableType === 'Company')
|
|
||||||
.map((relation) => relation.commentableId) ?? [];
|
|
||||||
|
|
||||||
const personsForMultiSelect = useFilteredSearchPeopleQuery({
|
|
||||||
searchFilter,
|
|
||||||
selectedIds: peopleIds,
|
|
||||||
});
|
|
||||||
|
|
||||||
const companiesForMultiSelect = useFilteredSearchCompanyQuery({
|
|
||||||
searchFilter,
|
|
||||||
selectedIds: companyIds,
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setHotkeyScopeAndMemorizePreviousScope,
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
goBackToPreviousHotkeyScope,
|
goBackToPreviousHotkeyScope,
|
||||||
} = usePreviousHotkeyScope();
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
function handleRelationContainerClick() {
|
const initialPeopleIds = useMemo(
|
||||||
|
() =>
|
||||||
|
commentThread?.commentThreadTargets
|
||||||
|
?.filter((relation) => relation.commentableType === 'Person')
|
||||||
|
.map((relation) => relation.commentableId) ?? [],
|
||||||
|
[commentThread?.commentThreadTargets],
|
||||||
|
);
|
||||||
|
const initialCompanyIds = useMemo(
|
||||||
|
() =>
|
||||||
|
commentThread?.commentThreadTargets
|
||||||
|
?.filter((relation) => relation.commentableType === 'Company')
|
||||||
|
.map((relation) => relation.commentableId) ?? [],
|
||||||
|
[commentThread?.commentThreadTargets],
|
||||||
|
);
|
||||||
|
|
||||||
|
const initialSelectedEntityIds = useMemo(
|
||||||
|
() =>
|
||||||
|
[...initialPeopleIds, ...initialCompanyIds].reduce<
|
||||||
|
Record<string, boolean>
|
||||||
|
>((result, entityId) => ({ ...result, [entityId]: true }), {}),
|
||||||
|
[initialPeopleIds, initialCompanyIds],
|
||||||
|
);
|
||||||
|
|
||||||
|
const personsForMultiSelect = useFilteredSearchPeopleQuery({
|
||||||
|
searchFilter,
|
||||||
|
selectedIds: initialPeopleIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
const companiesForMultiSelect = useFilteredSearchCompanyQuery({
|
||||||
|
searchFilter,
|
||||||
|
selectedIds: initialCompanyIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedEntities = flatMapAndSortEntityForSelectArrayOfArrayByName([
|
||||||
|
personsForMultiSelect.selectedEntities,
|
||||||
|
companiesForMultiSelect.selectedEntities,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const filteredSelectedEntities =
|
||||||
|
flatMapAndSortEntityForSelectArrayOfArrayByName([
|
||||||
|
personsForMultiSelect.filteredSelectedEntities,
|
||||||
|
companiesForMultiSelect.filteredSelectedEntities,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const entitiesToSelect = flatMapAndSortEntityForSelectArrayOfArrayByName([
|
||||||
|
personsForMultiSelect.entitiesToSelect,
|
||||||
|
companiesForMultiSelect.entitiesToSelect,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleCheckItemsChange = useHandleCheckableCommentThreadTargetChange({
|
||||||
|
commentThread,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exitEditMode = useCallback(() => {
|
||||||
|
goBackToPreviousHotkeyScope();
|
||||||
|
setIsMenuOpen(false);
|
||||||
|
setSearchFilter('');
|
||||||
|
|
||||||
|
if (Object.values(selectedEntityIds).some((value) => !!value)) {
|
||||||
|
handleCheckItemsChange(selectedEntityIds, entitiesToSelect);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
entitiesToSelect,
|
||||||
|
selectedEntityIds,
|
||||||
|
goBackToPreviousHotkeyScope,
|
||||||
|
handleCheckItemsChange,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleRelationContainerClick = useCallback(() => {
|
||||||
if (isMenuOpen) {
|
if (isMenuOpen) {
|
||||||
exitEditMode();
|
exitEditMode();
|
||||||
} else {
|
} else {
|
||||||
setIsMenuOpen(true);
|
setIsMenuOpen(true);
|
||||||
|
setSelectedEntityIds(initialSelectedEntityIds);
|
||||||
setHotkeyScopeAndMemorizePreviousScope(
|
setHotkeyScopeAndMemorizePreviousScope(
|
||||||
RelationPickerHotkeyScope.RelationPicker,
|
RelationPickerHotkeyScope.RelationPicker,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}, [
|
||||||
|
initialSelectedEntityIds,
|
||||||
// TODO: Place in a scoped recoil atom family
|
exitEditMode,
|
||||||
function handleFilterChange(newSearchFilter: string) {
|
isMenuOpen,
|
||||||
setSearchFilter(newSearchFilter);
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
}
|
]);
|
||||||
|
|
||||||
const handleCheckItemChange = useHandleCheckableCommentThreadTargetChange({
|
|
||||||
commentThread,
|
|
||||||
});
|
|
||||||
|
|
||||||
function exitEditMode() {
|
|
||||||
goBackToPreviousHotkeyScope();
|
|
||||||
setIsMenuOpen(false);
|
|
||||||
setSearchFilter('');
|
|
||||||
}
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
['esc', 'enter'],
|
['esc', 'enter'],
|
||||||
@ -159,22 +201,6 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedEntities = flatMapAndSortEntityForSelectArrayOfArrayByName([
|
|
||||||
personsForMultiSelect.selectedEntities,
|
|
||||||
companiesForMultiSelect.selectedEntities,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const filteredSelectedEntities =
|
|
||||||
flatMapAndSortEntityForSelectArrayOfArrayByName([
|
|
||||||
personsForMultiSelect.filteredSelectedEntities,
|
|
||||||
companiesForMultiSelect.filteredSelectedEntities,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const entitiesToSelect = flatMapAndSortEntityForSelectArrayOfArrayByName([
|
|
||||||
personsForMultiSelect.entitiesToSelect,
|
|
||||||
companiesForMultiSelect.entitiesToSelect,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledRelationContainer
|
<StyledRelationContainer
|
||||||
@ -204,9 +230,10 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
|||||||
selectedEntities,
|
selectedEntities,
|
||||||
loading: false, // TODO implement skeleton loading
|
loading: false, // TODO implement skeleton loading
|
||||||
}}
|
}}
|
||||||
onItemCheckChange={handleCheckItemChange}
|
onChange={setSelectedEntityIds}
|
||||||
onSearchFilterChange={handleFilterChange}
|
onSearchFilterChange={setSearchFilter}
|
||||||
searchFilter={searchFilter}
|
searchFilter={searchFilter}
|
||||||
|
value={selectedEntityIds}
|
||||||
/>
|
/>
|
||||||
</StyledMenuWrapper>
|
</StyledMenuWrapper>
|
||||||
</RecoilScope>
|
</RecoilScope>
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import { GET_PEOPLE } from '@/people/queries';
|
|||||||
import {
|
import {
|
||||||
CommentThread,
|
CommentThread,
|
||||||
CommentThreadTarget,
|
CommentThreadTarget,
|
||||||
useAddCommentThreadTargetOnCommentThreadMutation,
|
useAddCommentThreadTargetsOnCommentThreadMutation,
|
||||||
useRemoveCommentThreadTargetOnCommentThreadMutation,
|
useRemoveCommentThreadTargetsOnCommentThreadMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
import { GET_COMMENT_THREADS_BY_TARGETS } from '../queries';
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '../queries';
|
||||||
@ -22,8 +22,8 @@ export function useHandleCheckableCommentThreadTargetChange({
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
const [addCommentThreadTargetOnCommentThread] =
|
const [addCommentThreadTargetsOnCommentThread] =
|
||||||
useAddCommentThreadTargetOnCommentThreadMutation({
|
useAddCommentThreadTargetsOnCommentThreadMutation({
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
getOperationName(GET_COMPANIES) ?? '',
|
getOperationName(GET_COMPANIES) ?? '',
|
||||||
getOperationName(GET_PEOPLE) ?? '',
|
getOperationName(GET_PEOPLE) ?? '',
|
||||||
@ -31,8 +31,8 @@ export function useHandleCheckableCommentThreadTargetChange({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const [removeCommentThreadTargetOnCommentThread] =
|
const [removeCommentThreadTargetsOnCommentThread] =
|
||||||
useRemoveCommentThreadTargetOnCommentThreadMutation({
|
useRemoveCommentThreadTargetsOnCommentThreadMutation({
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
getOperationName(GET_COMPANIES) ?? '',
|
getOperationName(GET_COMPANIES) ?? '',
|
||||||
getOperationName(GET_PEOPLE) ?? '',
|
getOperationName(GET_PEOPLE) ?? '',
|
||||||
@ -40,36 +40,45 @@ export function useHandleCheckableCommentThreadTargetChange({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
return function handleCheckItemChange(
|
return async function handleCheckItemsChange(
|
||||||
newCheckedValue: boolean,
|
entityValues: Record<string, boolean>,
|
||||||
entity: CommentableEntityForSelect,
|
entities: CommentableEntityForSelect[],
|
||||||
) {
|
) {
|
||||||
if (!commentThread) {
|
if (!commentThread) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (newCheckedValue) {
|
|
||||||
addCommentThreadTargetOnCommentThread({
|
const currentEntityIds = commentThread.commentThreadTargets.map(
|
||||||
|
({ commentableId }) => commentableId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const entitiesToAdd = entities.filter(
|
||||||
|
({ id }) => entityValues[id] && !currentEntityIds.includes(id),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entitiesToAdd.length)
|
||||||
|
await addCommentThreadTargetsOnCommentThread({
|
||||||
variables: {
|
variables: {
|
||||||
commentableEntityId: entity.id,
|
|
||||||
commentableEntityType: entity.entityType,
|
|
||||||
commentThreadId: commentThread.id,
|
commentThreadId: commentThread.id,
|
||||||
commentThreadTargetCreationDate: new Date().toISOString(),
|
commentThreadTargetInputs: entitiesToAdd.map((entity) => ({
|
||||||
commentThreadTargetId: v4(),
|
id: v4(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
commentableType: entity.entityType,
|
||||||
|
commentableId: entity.id,
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
const foundCorrespondingTarget = commentThread.commentThreadTargets?.find(
|
|
||||||
(target) => target.commentableId === entity.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (foundCorrespondingTarget) {
|
const commentThreadTargetIdsToDelete = commentThread.commentThreadTargets
|
||||||
removeCommentThreadTargetOnCommentThread({
|
.filter(({ commentableId }) => !entityValues[commentableId])
|
||||||
variables: {
|
.map(({ id }) => id);
|
||||||
commentThreadId: commentThread.id,
|
|
||||||
commentThreadTargetId: foundCorrespondingTarget.id,
|
if (commentThreadTargetIdsToDelete.length)
|
||||||
},
|
await removeCommentThreadTargetsOnCommentThread({
|
||||||
});
|
variables: {
|
||||||
}
|
commentThreadId: commentThread.id,
|
||||||
}
|
commentThreadTargetIds: commentThreadTargetIdsToDelete,
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,26 +1,15 @@
|
|||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
export const ADD_COMMENT_THREAD_TARGET = gql`
|
export const ADD_COMMENT_THREAD_TARGETS = gql`
|
||||||
mutation AddCommentThreadTargetOnCommentThread(
|
mutation AddCommentThreadTargetsOnCommentThread(
|
||||||
$commentThreadId: String!
|
$commentThreadId: String!
|
||||||
$commentThreadTargetCreationDate: DateTime!
|
$commentThreadTargetInputs: [CommentThreadTargetCreateManyCommentThreadInput!]!
|
||||||
$commentThreadTargetId: String!
|
|
||||||
$commentableEntityId: String!
|
|
||||||
$commentableEntityType: CommentableType!
|
|
||||||
) {
|
) {
|
||||||
updateOneCommentThread(
|
updateOneCommentThread(
|
||||||
where: { id: $commentThreadId }
|
where: { id: $commentThreadId }
|
||||||
data: {
|
data: {
|
||||||
commentThreadTargets: {
|
commentThreadTargets: {
|
||||||
connectOrCreate: {
|
createMany: { data: $commentThreadTargetInputs }
|
||||||
create: {
|
|
||||||
id: $commentThreadTargetId
|
|
||||||
createdAt: $commentThreadTargetCreationDate
|
|
||||||
commentableType: $commentableEntityType
|
|
||||||
commentableId: $commentableEntityId
|
|
||||||
}
|
|
||||||
where: { id: $commentThreadTargetId }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@ -38,14 +27,18 @@ export const ADD_COMMENT_THREAD_TARGET = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const REMOVE_COMMENT_THREAD_TARGET = gql`
|
export const REMOVE_COMMENT_THREAD_TARGETS = gql`
|
||||||
mutation RemoveCommentThreadTargetOnCommentThread(
|
mutation RemoveCommentThreadTargetsOnCommentThread(
|
||||||
$commentThreadId: String!
|
$commentThreadId: String!
|
||||||
$commentThreadTargetId: String!
|
$commentThreadTargetIds: [String!]!
|
||||||
) {
|
) {
|
||||||
updateOneCommentThread(
|
updateOneCommentThread(
|
||||||
where: { id: $commentThreadId }
|
where: { id: $commentThreadId }
|
||||||
data: { commentThreadTargets: { delete: { id: $commentThreadTargetId } } }
|
data: {
|
||||||
|
commentThreadTargets: {
|
||||||
|
deleteMany: { id: { in: $commentThreadTargetIds } }
|
||||||
|
}
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
|
|||||||
@ -79,7 +79,8 @@ export function Checkbox({
|
|||||||
indeterminate,
|
indeterminate,
|
||||||
variant = CheckboxVariant.Primary,
|
variant = CheckboxVariant.Primary,
|
||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
const [isInternalChecked, setIsInternalChecked] = React.useState(false);
|
const [isInternalChecked, setIsInternalChecked] =
|
||||||
|
React.useState<boolean>(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setIsInternalChecked(checked);
|
setIsInternalChecked(checked);
|
||||||
|
|||||||
@ -23,17 +23,16 @@ export function MultipleEntitySelect<
|
|||||||
CustomEntityForSelect extends EntityForSelect,
|
CustomEntityForSelect extends EntityForSelect,
|
||||||
>({
|
>({
|
||||||
entities,
|
entities,
|
||||||
onItemCheckChange,
|
onChange,
|
||||||
onSearchFilterChange,
|
onSearchFilterChange,
|
||||||
searchFilter,
|
searchFilter,
|
||||||
|
value,
|
||||||
}: {
|
}: {
|
||||||
entities: EntitiesForMultipleEntitySelect<CustomEntityForSelect>;
|
entities: EntitiesForMultipleEntitySelect<CustomEntityForSelect>;
|
||||||
searchFilter: string;
|
searchFilter: string;
|
||||||
onSearchFilterChange: (newSearchFilter: string) => void;
|
onSearchFilterChange: (newSearchFilter: string) => void;
|
||||||
onItemCheckChange: (
|
onChange: (value: Record<string, boolean>) => void;
|
||||||
newCheckedValue: boolean,
|
value: Record<string, boolean>;
|
||||||
entity: CustomEntityForSelect,
|
|
||||||
) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const debouncedSetSearchFilter = debounce(onSearchFilterChange, 100, {
|
const debouncedSetSearchFilter = debounce(onSearchFilterChange, 100, {
|
||||||
leading: true,
|
leading: true,
|
||||||
@ -61,13 +60,9 @@ export function MultipleEntitySelect<
|
|||||||
{entitiesInDropdown?.map((entity) => (
|
{entitiesInDropdown?.map((entity) => (
|
||||||
<DropdownMenuCheckableItem
|
<DropdownMenuCheckableItem
|
||||||
key={entity.id}
|
key={entity.id}
|
||||||
checked={
|
checked={value[entity.id]}
|
||||||
entities.selectedEntities
|
|
||||||
?.map((selectedEntity) => selectedEntity.id)
|
|
||||||
?.includes(entity.id) ?? false
|
|
||||||
}
|
|
||||||
onChange={(newCheckedValue) =>
|
onChange={(newCheckedValue) =>
|
||||||
onItemCheckChange(newCheckedValue, entity)
|
onChange({ ...value, [entity.id]: newCheckedValue })
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
Reference in New Issue
Block a user