diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index e15638ab1..e6d28a1ac 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -829,6 +829,13 @@ export type EnumPipelineProgressableTypeFilter = { notIn?: InputMaybe>; }; +export type EnumViewFilterOperandFilter = { + equals?: InputMaybe; + in?: InputMaybe>; + not?: InputMaybe; + notIn?: InputMaybe>; +}; + export type EnumViewSortDirectionFilter = { equals?: InputMaybe; in?: InputMaybe>; @@ -969,6 +976,7 @@ export type Mutation = { createManyPerson: AffectedRows; createManyView: AffectedRows; createManyViewField: AffectedRows; + createManyViewFilter: AffectedRows; createManyViewSort: AffectedRows; createOneActivity: Activity; createOneComment: Comment; @@ -983,6 +991,7 @@ export type Mutation = { deleteManyPerson: AffectedRows; deleteManyPipelineProgress: AffectedRows; deleteManyView: AffectedRows; + deleteManyViewFilter: AffectedRows; deleteManyViewSort: AffectedRows; deleteUserAccount: User; deleteWorkspaceMember: WorkspaceMember; @@ -996,6 +1005,7 @@ export type Mutation = { updateOnePipelineStage?: Maybe; updateOneView: View; updateOneViewField: ViewField; + updateOneViewFilter: ViewFilter; updateOneViewSort: ViewSort; updateUser: User; updateWorkspace: Workspace; @@ -1060,6 +1070,12 @@ export type MutationCreateManyViewFieldArgs = { }; +export type MutationCreateManyViewFilterArgs = { + data: Array; + skipDuplicates?: InputMaybe; +}; + + export type MutationCreateManyViewSortArgs = { data: Array; skipDuplicates?: InputMaybe; @@ -1126,6 +1142,11 @@ export type MutationDeleteManyViewArgs = { }; +export type MutationDeleteManyViewFilterArgs = { + where?: InputMaybe; +}; + + export type MutationDeleteManyViewSortArgs = { where?: InputMaybe; }; @@ -1195,6 +1216,12 @@ export type MutationUpdateOneViewFieldArgs = { }; +export type MutationUpdateOneViewFilterArgs = { + data: ViewFilterUpdateInput; + where: ViewFilterWhereUniqueInput; +}; + + export type MutationUpdateOneViewSortArgs = { data: ViewSortUpdateInput; where: ViewSortWhereUniqueInput; @@ -1305,6 +1332,13 @@ export type NestedEnumPipelineProgressableTypeFilter = { notIn?: InputMaybe>; }; +export type NestedEnumViewFilterOperandFilter = { + equals?: InputMaybe; + in?: InputMaybe>; + not?: InputMaybe; + notIn?: InputMaybe>; +}; + export type NestedEnumViewSortDirectionFilter = { equals?: InputMaybe; in?: InputMaybe>; @@ -1930,6 +1964,7 @@ export type Query = { findManyUser: Array; findManyView: Array; findManyViewField: Array; + findManyViewFilter: Array; findManyViewSort: Array; findManyWorkspaceMember: Array; findUniqueCompany: Company; @@ -2038,6 +2073,16 @@ export type QueryFindManyViewFieldArgs = { }; +export type QueryFindManyViewFilterArgs = { + cursor?: InputMaybe; + distinct?: InputMaybe>; + orderBy?: InputMaybe>; + skip?: InputMaybe; + take?: InputMaybe; + where?: InputMaybe; +}; + + export type QueryFindManyViewSortArgs = { cursor?: InputMaybe; distinct?: InputMaybe>; @@ -2349,6 +2394,7 @@ export type Verify = { export type View = { __typename?: 'View'; fields?: Maybe>; + filters?: Maybe>; id: Scalars['ID']; name: Scalars['String']; objectId: Scalars['String']; @@ -2478,8 +2524,111 @@ export type ViewFieldWorkspaceIdViewIdObjectNameFieldNameCompoundUniqueInput = { viewId: Scalars['String']; }; +export type ViewFilter = { + __typename?: 'ViewFilter'; + displayValue: Scalars['String']; + key: Scalars['String']; + name: Scalars['String']; + operand: ViewFilterOperand; + value: Scalars['String']; + view: View; + viewId: Scalars['String']; +}; + +export type ViewFilterCreateManyInput = { + displayValue: Scalars['String']; + key: Scalars['String']; + name: Scalars['String']; + operand: ViewFilterOperand; + value: Scalars['String']; + viewId: Scalars['String']; +}; + +export type ViewFilterListRelationFilter = { + every?: InputMaybe; + none?: InputMaybe; + some?: InputMaybe; +}; + +export enum ViewFilterOperand { + Contains = 'Contains', + DoesNotContain = 'DoesNotContain', + GreaterThan = 'GreaterThan', + Is = 'Is', + IsNot = 'IsNot', + LessThan = 'LessThan' +} + +export type ViewFilterOrderByRelationAggregateInput = { + _count?: InputMaybe; +}; + +export type ViewFilterOrderByWithRelationInput = { + displayValue?: InputMaybe; + key?: InputMaybe; + name?: InputMaybe; + operand?: InputMaybe; + value?: InputMaybe; + view?: InputMaybe; + viewId?: InputMaybe; +}; + +export enum ViewFilterScalarFieldEnum { + DisplayValue = 'displayValue', + Key = 'key', + Name = 'name', + Operand = 'operand', + Value = 'value', + ViewId = 'viewId', + WorkspaceId = 'workspaceId' +} + +export type ViewFilterUpdateInput = { + displayValue?: InputMaybe; + key?: InputMaybe; + name?: InputMaybe; + operand?: InputMaybe; + value?: InputMaybe; + view?: InputMaybe; +}; + +export type ViewFilterUpdateManyWithoutViewNestedInput = { + connect?: InputMaybe>; + disconnect?: InputMaybe>; + set?: InputMaybe>; +}; + +export type ViewFilterUpdateManyWithoutWorkspaceNestedInput = { + connect?: InputMaybe>; + disconnect?: InputMaybe>; + set?: InputMaybe>; +}; + +export type ViewFilterViewIdKeyCompoundUniqueInput = { + key: Scalars['String']; + viewId: Scalars['String']; +}; + +export type ViewFilterWhereInput = { + AND?: InputMaybe>; + NOT?: InputMaybe>; + OR?: InputMaybe>; + displayValue?: InputMaybe; + key?: InputMaybe; + name?: InputMaybe; + operand?: InputMaybe; + value?: InputMaybe; + view?: InputMaybe; + viewId?: InputMaybe; +}; + +export type ViewFilterWhereUniqueInput = { + viewId_key?: InputMaybe; +}; + export type ViewOrderByWithRelationInput = { fields?: InputMaybe; + filters?: InputMaybe; id?: InputMaybe; name?: InputMaybe; objectId?: InputMaybe; @@ -2593,6 +2742,7 @@ export enum ViewType { export type ViewUpdateInput = { fields?: InputMaybe; + filters?: InputMaybe; id?: InputMaybe; name?: InputMaybe; objectId?: InputMaybe; @@ -2606,6 +2756,10 @@ export type ViewUpdateManyWithoutWorkspaceNestedInput = { set?: InputMaybe>; }; +export type ViewUpdateOneRequiredWithoutFiltersNestedInput = { + connect?: InputMaybe; +}; + export type ViewUpdateOneRequiredWithoutSortsNestedInput = { connect?: InputMaybe; }; @@ -2620,6 +2774,7 @@ export type ViewWhereInput = { NOT?: InputMaybe>; OR?: InputMaybe>; fields?: InputMaybe; + filters?: InputMaybe; id?: InputMaybe; name?: InputMaybe; objectId?: InputMaybe; @@ -2657,6 +2812,7 @@ export type Workspace = { pipelines?: Maybe>; updatedAt: Scalars['DateTime']; viewFields?: Maybe>; + viewFilters?: Maybe>; viewSorts?: Maybe>; views?: Maybe>; workspaceMember?: Maybe>; @@ -2741,6 +2897,7 @@ export type WorkspaceUpdateInput = { pipelines?: InputMaybe; updatedAt?: InputMaybe; viewFields?: InputMaybe; + viewFilters?: InputMaybe; viewSorts?: InputMaybe; views?: InputMaybe; workspaceMember?: InputMaybe; @@ -2838,7 +2995,7 @@ export type CreateEventMutationVariables = Exact<{ export type CreateEventMutation = { __typename?: 'Mutation', createEvent: { __typename?: 'Analytics', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, avatarUrl?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }; export type ChallengeMutationVariables = Exact<{ email: Scalars['String']; @@ -2853,7 +3010,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, avatarUrl?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ refreshToken: Scalars['String']; @@ -2876,7 +3033,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null, canImpersonate: boolean, supportUserHash?: string | null, avatarUrl?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, allowImpersonation: boolean, workspace: { __typename?: 'Workspace', id: string, domainName?: string | null, displayName?: string | null, logo?: string | null, inviteHash?: string | null } } | null, settings: { __typename?: 'UserSettings', id: string, colorScheme: ColorScheme, locale: string } }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -3216,6 +3373,13 @@ export type CreateViewFieldsMutationVariables = Exact<{ export type CreateViewFieldsMutation = { __typename?: 'Mutation', createManyViewField: { __typename?: 'AffectedRows', count: number } }; +export type CreateViewFiltersMutationVariables = Exact<{ + data: Array | ViewFilterCreateManyInput; +}>; + + +export type CreateViewFiltersMutation = { __typename?: 'Mutation', createManyViewFilter: { __typename?: 'AffectedRows', count: number } }; + export type CreateViewSortsMutationVariables = Exact<{ data: Array | ViewSortCreateManyInput; }>; @@ -3230,7 +3394,6 @@ export type CreateViewsMutationVariables = Exact<{ export type CreateViewsMutation = { __typename?: 'Mutation', createManyView: { __typename?: 'AffectedRows', count: number } }; - export type DeleteViewsMutationVariables = Exact<{ where: ViewWhereInput; }>; @@ -3238,6 +3401,12 @@ export type DeleteViewsMutationVariables = Exact<{ export type DeleteViewsMutation = { __typename?: 'Mutation', deleteManyView: { __typename?: 'AffectedRows', count: number } }; +export type DeleteViewFiltersMutationVariables = Exact<{ + where: ViewFilterWhereInput; +}>; + + +export type DeleteViewFiltersMutation = { __typename?: 'Mutation', deleteManyViewFilter: { __typename?: 'AffectedRows', count: number } }; export type DeleteViewSortsMutationVariables = Exact<{ where: ViewSortWhereInput; @@ -3262,6 +3431,14 @@ export type UpdateViewFieldMutationVariables = Exact<{ export type UpdateViewFieldMutation = { __typename?: 'Mutation', updateOneViewField: { __typename?: 'ViewField', id: string, fieldName: string, isVisible: boolean, sizeInPx: number, index: number } }; +export type UpdateViewFilterMutationVariables = Exact<{ + data: ViewFilterUpdateInput; + where: ViewFilterWhereUniqueInput; +}>; + + +export type UpdateViewFilterMutation = { __typename?: 'Mutation', viewFilter: { __typename?: 'ViewFilter', displayValue: string, key: string, name: string, operand: ViewFilterOperand, value: string } }; + export type UpdateViewSortMutationVariables = Exact<{ data: ViewSortUpdateInput; where: ViewSortWhereUniqueInput; @@ -3278,6 +3455,13 @@ export type GetViewFieldsQueryVariables = Exact<{ export type GetViewFieldsQuery = { __typename?: 'Query', viewFields: Array<{ __typename?: 'ViewField', id: string, fieldName: string, isVisible: boolean, sizeInPx: number, index: number }> }; +export type GetViewFiltersQueryVariables = Exact<{ + where?: InputMaybe; +}>; + + +export type GetViewFiltersQuery = { __typename?: 'Query', viewFilters: Array<{ __typename?: 'ViewFilter', displayValue: string, key: string, name: string, operand: ViewFilterOperand, value: string }> }; + export type GetViewSortsQueryVariables = Exact<{ where?: InputMaybe; }>; @@ -5934,6 +6118,39 @@ export function useCreateViewFieldsMutation(baseOptions?: Apollo.MutationHookOpt export type CreateViewFieldsMutationHookResult = ReturnType; export type CreateViewFieldsMutationResult = Apollo.MutationResult; export type CreateViewFieldsMutationOptions = Apollo.BaseMutationOptions; +export const CreateViewFiltersDocument = gql` + mutation CreateViewFilters($data: [ViewFilterCreateManyInput!]!) { + createManyViewFilter(data: $data) { + count + } +} + `; +export type CreateViewFiltersMutationFn = Apollo.MutationFunction; + +/** + * __useCreateViewFiltersMutation__ + * + * To run a mutation, you first call `useCreateViewFiltersMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateViewFiltersMutation` returns a tuple that includes: + * - 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 + * + * @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 + * const [createViewFiltersMutation, { data, loading, error }] = useCreateViewFiltersMutation({ + * variables: { + * data: // value for 'data' + * }, + * }); + */ +export function useCreateViewFiltersMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreateViewFiltersDocument, options); + } +export type CreateViewFiltersMutationHookResult = ReturnType; +export type CreateViewFiltersMutationResult = Apollo.MutationResult; +export type CreateViewFiltersMutationOptions = Apollo.BaseMutationOptions; export const CreateViewSortsDocument = gql` mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) { createManyViewSort(data: $data) { @@ -6000,7 +6217,6 @@ export function useCreateViewsMutation(baseOptions?: Apollo.MutationHookOptions< export type CreateViewsMutationHookResult = ReturnType; export type CreateViewsMutationResult = Apollo.MutationResult; export type CreateViewsMutationOptions = Apollo.BaseMutationOptions; - export const DeleteViewsDocument = gql` mutation DeleteViews($where: ViewWhereInput!) { deleteManyView(where: $where) { @@ -6034,7 +6250,39 @@ export function useDeleteViewsMutation(baseOptions?: Apollo.MutationHookOptions< export type DeleteViewsMutationHookResult = ReturnType; export type DeleteViewsMutationResult = Apollo.MutationResult; export type DeleteViewsMutationOptions = Apollo.BaseMutationOptions; +export const DeleteViewFiltersDocument = gql` + mutation DeleteViewFilters($where: ViewFilterWhereInput!) { + deleteManyViewFilter(where: $where) { + count + } +} + `; +export type DeleteViewFiltersMutationFn = Apollo.MutationFunction; +/** + * __useDeleteViewFiltersMutation__ + * + * To run a mutation, you first call `useDeleteViewFiltersMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useDeleteViewFiltersMutation` returns a tuple that includes: + * - 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 + * + * @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 + * const [deleteViewFiltersMutation, { data, loading, error }] = useDeleteViewFiltersMutation({ + * variables: { + * where: // value for 'where' + * }, + * }); + */ +export function useDeleteViewFiltersMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(DeleteViewFiltersDocument, options); + } +export type DeleteViewFiltersMutationHookResult = ReturnType; +export type DeleteViewFiltersMutationResult = Apollo.MutationResult; +export type DeleteViewFiltersMutationOptions = Apollo.BaseMutationOptions; export const DeleteViewSortsDocument = gql` mutation DeleteViewSorts($where: ViewSortWhereInput!) { deleteManyViewSort(where: $where) { @@ -6141,6 +6389,44 @@ export function useUpdateViewFieldMutation(baseOptions?: Apollo.MutationHookOpti export type UpdateViewFieldMutationHookResult = ReturnType; export type UpdateViewFieldMutationResult = Apollo.MutationResult; export type UpdateViewFieldMutationOptions = Apollo.BaseMutationOptions; +export const UpdateViewFilterDocument = gql` + mutation UpdateViewFilter($data: ViewFilterUpdateInput!, $where: ViewFilterWhereUniqueInput!) { + viewFilter: updateOneViewFilter(data: $data, where: $where) { + displayValue + key + name + operand + value + } +} + `; +export type UpdateViewFilterMutationFn = Apollo.MutationFunction; + +/** + * __useUpdateViewFilterMutation__ + * + * To run a mutation, you first call `useUpdateViewFilterMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateViewFilterMutation` returns a tuple that includes: + * - 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 + * + * @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 + * const [updateViewFilterMutation, { data, loading, error }] = useUpdateViewFilterMutation({ + * variables: { + * data: // value for 'data' + * where: // value for 'where' + * }, + * }); + */ +export function useUpdateViewFilterMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(UpdateViewFilterDocument, options); + } +export type UpdateViewFilterMutationHookResult = ReturnType; +export type UpdateViewFilterMutationResult = Apollo.MutationResult; +export type UpdateViewFilterMutationOptions = Apollo.BaseMutationOptions; export const UpdateViewSortDocument = gql` mutation UpdateViewSort($data: ViewSortUpdateInput!, $where: ViewSortWhereUniqueInput!) { viewSort: updateOneViewSort(data: $data, where: $where) { @@ -6217,6 +6503,45 @@ export function useGetViewFieldsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpti export type GetViewFieldsQueryHookResult = ReturnType; export type GetViewFieldsLazyQueryHookResult = ReturnType; export type GetViewFieldsQueryResult = Apollo.QueryResult; +export const GetViewFiltersDocument = gql` + query GetViewFilters($where: ViewFilterWhereInput) { + viewFilters: findManyViewFilter(where: $where) { + displayValue + key + name + operand + value + } +} + `; + +/** + * __useGetViewFiltersQuery__ + * + * To run a query within a React component, call `useGetViewFiltersQuery` and pass it any options that fit your needs. + * When your component renders, `useGetViewFiltersQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetViewFiltersQuery({ + * variables: { + * where: // value for 'where' + * }, + * }); + */ +export function useGetViewFiltersQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetViewFiltersDocument, options); + } +export function useGetViewFiltersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetViewFiltersDocument, options); + } +export type GetViewFiltersQueryHookResult = ReturnType; +export type GetViewFiltersLazyQueryHookResult = ReturnType; +export type GetViewFiltersQueryResult = Apollo.QueryResult; export const GetViewSortsDocument = gql` query GetViewSorts($where: ViewSortWhereInput) { viewSorts: findManyViewSort(where: $where) { diff --git a/front/src/modules/activities/hooks/useTasks.ts b/front/src/modules/activities/hooks/useTasks.ts index 2840ec02a..8a61ba5b9 100644 --- a/front/src/modules/activities/hooks/useTasks.ts +++ b/front/src/modules/activities/hooks/useTasks.ts @@ -4,6 +4,7 @@ import { useRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState'; +import { FilterOperand } from '@/ui/filter-n-sort/types/FilterOperand'; import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause'; import { activeTabIdScopedState } from '@/ui/tab/states/activeTabIdScopedState'; import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState'; @@ -37,10 +38,10 @@ export function useTasks() { if (currentUser && !filters.length) { setFilters([ { - field: 'assigneeId', + key: 'assigneeId', type: 'entity', value: currentUser.id, - operand: 'is', + operand: FilterOperand.Is, displayValue: currentUser.displayName, displayAvatarUrl: currentUser.avatarUrl ?? undefined, }, diff --git a/front/src/modules/companies/table/components/CompanyTable.tsx b/front/src/modules/companies/table/components/CompanyTable.tsx index 3169330de..7252ea024 100644 --- a/front/src/modules/companies/table/components/CompanyTable.tsx +++ b/front/src/modules/companies/table/components/CompanyTable.tsx @@ -1,20 +1,20 @@ -import { useMemo } from 'react'; +import { useCallback, useMemo } from 'react'; import { companyViewFields } from '@/companies/constants/companyViewFields'; import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries'; import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries'; import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport'; import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState'; -import { sortsOrderByScopedState } from '@/ui/filter-n-sort/states/sortScopedState'; +import { sortsOrderByScopedSelector } from '@/ui/filter-n-sort/states/sortsOrderByScopedSelector'; import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause'; import { EntityTable } from '@/ui/table/components/EntityTable'; import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData'; import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem'; import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext'; -import { currentTableViewIdState } from '@/ui/table/states/tableViewsState'; import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; import { useTableViewFields } from '@/views/hooks/useTableViewFields'; import { useTableViews } from '@/views/hooks/useTableViews'; +import { useViewFilters } from '@/views/hooks/useViewFilters'; import { useViewSorts } from '@/views/hooks/useViewSorts'; import { SortOrder, @@ -26,12 +26,8 @@ import { companiesFilters } from '~/pages/companies/companies-filters'; import { availableSorts } from '~/pages/companies/companies-sorts'; export function CompanyTable() { - const currentViewId = useRecoilScopedValue( - currentTableViewIdState, - TableRecoilScopeContext, - ); const orderBy = useRecoilScopedValue( - sortsOrderByScopedState, + sortsOrderByScopedSelector, TableRecoilScopeContext, ); const [updateEntityMutation] = useUpdateOneCompanyMutation(); @@ -44,7 +40,10 @@ export function CompanyTable() { viewFieldDefinitions: companyViewFields, }); - const { handleSortsChange } = useViewSorts({ availableSorts }); + const { persistFilters } = useViewFilters({ + availableFilters: companiesFilters, + }); + const { persistSorts } = useViewSorts({ availableSorts }); const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport(); const filters = useRecoilScopedValue( @@ -59,6 +58,11 @@ export function CompanyTable() { const { setContextMenuEntries } = useCompanyTableContextMenuEntries(); const { setActionBarEntries } = useCompanyTableActionBarEntries(); + const handleViewSubmit = useCallback(async () => { + await persistFilters(); + await persistSorts(); + }, [persistFilters, persistSorts]); + function handleImport() { openCompanySpreadsheetImport(); } @@ -68,15 +72,7 @@ export function CompanyTable() { { + await persistFilters(); + await persistSorts(); + }, [persistFilters, persistSorts]); + function handleImport() { openPersonSpreadsheetImport(); } @@ -67,15 +71,7 @@ export function PeopleTable() { & { - children: React.ReactElement[]; + children: ReactNode[]; }; export function ButtonGroup({ children, variant, size }: ButtonGroupProps) { return ( {React.Children.map(children, (child, index) => { + if (!React.isValidElement(child)) return null; + let position: ButtonPosition; if (index === 0) { diff --git a/front/src/modules/ui/filter-n-sort/components/FilterDropdownDateSearchInput.tsx b/front/src/modules/ui/filter-n-sort/components/FilterDropdownDateSearchInput.tsx index 78d8612c6..608fdc63d 100644 --- a/front/src/modules/ui/filter-n-sort/components/FilterDropdownDateSearchInput.tsx +++ b/front/src/modules/ui/filter-n-sort/components/FilterDropdownDateSearchInput.tsx @@ -28,7 +28,7 @@ export function FilterDropdownDateSearchInput({ if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return; upsertFilter({ - field: filterDefinitionUsedInDropdown.field, + key: filterDefinitionUsedInDropdown.key, type: filterDefinitionUsedInDropdown.type, value: date.toISOString(), operand: selectedOperandInDropdown, diff --git a/front/src/modules/ui/filter-n-sort/components/FilterDropdownEntitySearchSelect.tsx b/front/src/modules/ui/filter-n-sort/components/FilterDropdownEntitySearchSelect.tsx index 6f50798ec..235ed8c07 100644 --- a/front/src/modules/ui/filter-n-sort/components/FilterDropdownEntitySearchSelect.tsx +++ b/front/src/modules/ui/filter-n-sort/components/FilterDropdownEntitySearchSelect.tsx @@ -51,14 +51,14 @@ export function FilterDropdownEntitySearchSelect({ selectedEntity.id === filterDropdownSelectedEntityId; if (clickedOnAlreadySelectedEntity) { - removeFilter(filterDefinitionUsedInDropdown.field); + removeFilter(filterDefinitionUsedInDropdown.key); setFilterDropdownSelectedEntityId(null); } else { setFilterDropdownSelectedEntityId(selectedEntity.id); upsertFilter({ displayValue: selectedEntity.name, - field: filterDefinitionUsedInDropdown.field, + key: filterDefinitionUsedInDropdown.key, operand: selectedOperandInDropdown, type: filterDefinitionUsedInDropdown.type, value: selectedEntity.id, diff --git a/front/src/modules/ui/filter-n-sort/components/FilterDropdownNumberSearchInput.tsx b/front/src/modules/ui/filter-n-sort/components/FilterDropdownNumberSearchInput.tsx index 5020d3f88..b95451667 100644 --- a/front/src/modules/ui/filter-n-sort/components/FilterDropdownNumberSearchInput.tsx +++ b/front/src/modules/ui/filter-n-sort/components/FilterDropdownNumberSearchInput.tsx @@ -34,10 +34,10 @@ export function FilterDropdownNumberSearchInput({ placeholder={filterDefinitionUsedInDropdown.label} onChange={(event: ChangeEvent) => { if (event.target.value === '') { - removeFilter(filterDefinitionUsedInDropdown.field); + removeFilter(filterDefinitionUsedInDropdown.key); } else { upsertFilter({ - field: filterDefinitionUsedInDropdown.field, + key: filterDefinitionUsedInDropdown.key, type: filterDefinitionUsedInDropdown.type, value: event.target.value, operand: selectedOperandInDropdown, diff --git a/front/src/modules/ui/filter-n-sort/components/FilterDropdownOperandSelect.tsx b/front/src/modules/ui/filter-n-sort/components/FilterDropdownOperandSelect.tsx index 08d8cf86d..cdb6bc0bd 100644 --- a/front/src/modules/ui/filter-n-sort/components/FilterDropdownOperandSelect.tsx +++ b/front/src/modules/ui/filter-n-sort/components/FilterDropdownOperandSelect.tsx @@ -48,7 +48,7 @@ export function FilterDropdownOperandSelect({ if (filterDefinitionUsedInDropdown && filterCurrentlyEdited) { upsertFilter({ - field: filterCurrentlyEdited.field, + key: filterCurrentlyEdited.key, displayValue: filterCurrentlyEdited.displayValue, operand: newOperand, type: filterCurrentlyEdited.type, diff --git a/front/src/modules/ui/filter-n-sort/components/FilterDropdownTextSearchInput.tsx b/front/src/modules/ui/filter-n-sort/components/FilterDropdownTextSearchInput.tsx index 6b62e90bf..148f8308b 100644 --- a/front/src/modules/ui/filter-n-sort/components/FilterDropdownTextSearchInput.tsx +++ b/front/src/modules/ui/filter-n-sort/components/FilterDropdownTextSearchInput.tsx @@ -44,10 +44,10 @@ export function FilterDropdownTextSearchInput({ setFilterDropdownSearchInput(event.target.value); if (event.target.value === '') { - removeFilter(filterDefinitionUsedInDropdown.field); + removeFilter(filterDefinitionUsedInDropdown.key); } else { upsertFilter({ - field: filterDefinitionUsedInDropdown.field, + key: filterDefinitionUsedInDropdown.key, type: filterDefinitionUsedInDropdown.type, value: event.target.value, operand: selectedOperandInDropdown, diff --git a/front/src/modules/ui/filter-n-sort/components/SortAndFilterBar.tsx b/front/src/modules/ui/filter-n-sort/components/SortAndFilterBar.tsx index 0ce016227..926ec075a 100644 --- a/front/src/modules/ui/filter-n-sort/components/SortAndFilterBar.tsx +++ b/front/src/modules/ui/filter-n-sort/components/SortAndFilterBar.tsx @@ -1,4 +1,4 @@ -import { Context } from 'react'; +import type { Context, ReactNode } from 'react'; import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; @@ -26,6 +26,7 @@ type OwnProps = { onRemoveSort: (sortId: SelectedSortType['key']) => void; onCancelClick: () => void; hasFilterButton?: boolean; + rightComponent?: ReactNode; }; const StyledBar = styled.div` @@ -97,6 +98,7 @@ function SortAndFilterBar({ onRemoveSort, onCancelClick, hasFilterButton = false, + rightComponent, }: OwnProps) { const theme = useTheme(); @@ -117,7 +119,7 @@ function SortAndFilterBar({ const filtersWithDefinition = filters.map((filter) => { const filterDefinition = availableFilters.find((availableFilter) => { - return availableFilter.field === filter.field; + return availableFilter.key === filter.key; }); return { @@ -170,15 +172,15 @@ function SortAndFilterBar({ {filtersWithDefinition.map((filter) => { return ( { - removeFilter(filter.field); + removeFilter(filter.key); }} /> ); @@ -190,18 +192,19 @@ function SortAndFilterBar({ HotkeyScope={FiltersHotkeyScope.FilterDropdownButton} color={theme.font.color.tertiary} icon={} - label={`Add filter`} + label="Add filter" /> )} {filters.length + sorts.length > 0 && ( Cancel )} + {rightComponent} ); } diff --git a/front/src/modules/ui/filter-n-sort/hooks/useFilterCurrentlyEdited.ts b/front/src/modules/ui/filter-n-sort/hooks/useFilterCurrentlyEdited.ts index 17abb2a55..81be332ce 100644 --- a/front/src/modules/ui/filter-n-sort/hooks/useFilterCurrentlyEdited.ts +++ b/front/src/modules/ui/filter-n-sort/hooks/useFilterCurrentlyEdited.ts @@ -15,7 +15,7 @@ export function useFilterCurrentlyEdited(context: Context) { return useMemo(() => { return filters.find( - (filter) => filter.field === filterDefinitionUsedInDropdown?.field, + (filter) => filter.key === filterDefinitionUsedInDropdown?.key, ); }, [filterDefinitionUsedInDropdown, filters]); } diff --git a/front/src/modules/ui/filter-n-sort/hooks/useRemoveFilter.ts b/front/src/modules/ui/filter-n-sort/hooks/useRemoveFilter.ts index a4e6f2bf2..4f71721f4 100644 --- a/front/src/modules/ui/filter-n-sort/hooks/useRemoveFilter.ts +++ b/front/src/modules/ui/filter-n-sort/hooks/useRemoveFilter.ts @@ -7,10 +7,10 @@ import { filtersScopedState } from '../states/filtersScopedState'; export function useRemoveFilter(context: Context) { const [, setFilters] = useRecoilScopedState(filtersScopedState, context); - return function removeFilter(filterField: string) { + return function removeFilter(filterKey: string) { setFilters((filters) => { return filters.filter((filter) => { - return filter.field !== filterField; + return filter.key !== filterKey; }); }); }; diff --git a/front/src/modules/ui/filter-n-sort/hooks/useUpsertFilter.ts b/front/src/modules/ui/filter-n-sort/hooks/useUpsertFilter.ts index 215204a62..5caf5cfa2 100644 --- a/front/src/modules/ui/filter-n-sort/hooks/useUpsertFilter.ts +++ b/front/src/modules/ui/filter-n-sort/hooks/useUpsertFilter.ts @@ -13,7 +13,7 @@ export function useUpsertFilter(context: Context) { setFilters((filters) => { return produce(filters, (filtersDraft) => { const index = filtersDraft.findIndex( - (filter) => filter.field === filterToUpsert.field, + (filter) => filter.key === filterToUpsert.key, ); if (index === -1) { diff --git a/front/src/modules/ui/filter-n-sort/states/filtersScopedState.ts b/front/src/modules/ui/filter-n-sort/states/filtersScopedState.ts index ddc5f8200..3f3ae4f17 100644 --- a/front/src/modules/ui/filter-n-sort/states/filtersScopedState.ts +++ b/front/src/modules/ui/filter-n-sort/states/filtersScopedState.ts @@ -1,6 +1,6 @@ import { atomFamily } from 'recoil'; -import { Filter } from '../types/Filter'; +import type { Filter } from '../types/Filter'; export const filtersScopedState = atomFamily({ key: 'filtersScopedState', diff --git a/front/src/modules/ui/filter-n-sort/states/savedFiltersByKeyScopedSelector.ts b/front/src/modules/ui/filter-n-sort/states/savedFiltersByKeyScopedSelector.ts new file mode 100644 index 000000000..0f797d22e --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/savedFiltersByKeyScopedSelector.ts @@ -0,0 +1,16 @@ +import { selectorFamily } from 'recoil'; + +import type { Filter } from '../types/Filter'; + +import { savedFiltersScopedState } from './savedFiltersScopedState'; + +export const savedFiltersByKeyScopedSelector = selectorFamily({ + key: 'savedFiltersByKeyScopedSelector', + get: + (param: string | undefined) => + ({ get }) => + get(savedFiltersScopedState(param)).reduce>( + (result, filter) => ({ ...result, [filter.key]: filter }), + {}, + ), +}); diff --git a/front/src/modules/ui/filter-n-sort/states/savedFiltersScopedState.ts b/front/src/modules/ui/filter-n-sort/states/savedFiltersScopedState.ts new file mode 100644 index 000000000..6dec10fa0 --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/savedFiltersScopedState.ts @@ -0,0 +1,10 @@ +import { atomFamily } from 'recoil'; + +import type { Filter } from '../types/Filter'; + +export const savedFiltersScopedState = atomFamily( + { + key: 'savedFiltersScopedState', + default: [], + }, +); diff --git a/front/src/modules/ui/filter-n-sort/states/savedSortsByKeyScopedSelector.ts b/front/src/modules/ui/filter-n-sort/states/savedSortsByKeyScopedSelector.ts new file mode 100644 index 000000000..5e9971fe5 --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/savedSortsByKeyScopedSelector.ts @@ -0,0 +1,15 @@ +import { selectorFamily } from 'recoil'; + +import type { SelectedSortType } from '../types/interface'; + +import { savedSortsScopedState } from './savedSortsScopedState'; + +export const savedSortsByKeyScopedSelector = selectorFamily({ + key: 'savedSortsByKeyScopedSelector', + get: + (viewId: string | undefined) => + ({ get }) => + get(savedSortsScopedState(viewId)).reduce< + Record> + >((result, sort) => ({ ...result, [sort.key]: sort }), {}), +}); diff --git a/front/src/modules/ui/filter-n-sort/states/savedSortsScopedState.ts b/front/src/modules/ui/filter-n-sort/states/savedSortsScopedState.ts new file mode 100644 index 000000000..bdf1679e8 --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/savedSortsScopedState.ts @@ -0,0 +1,11 @@ +import { atomFamily } from 'recoil'; + +import type { SelectedSortType } from '../types/interface'; + +export const savedSortsScopedState = atomFamily< + SelectedSortType[], + string | undefined +>({ + key: 'savedSortsScopedState', + default: [], +}); diff --git a/front/src/modules/ui/filter-n-sort/states/sortScopedState.ts b/front/src/modules/ui/filter-n-sort/states/sortScopedState.ts deleted file mode 100644 index 7d9021a24..000000000 --- a/front/src/modules/ui/filter-n-sort/states/sortScopedState.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { atomFamily, selectorFamily } from 'recoil'; - -import { reduceSortsToOrderBy } from '../helpers'; -import { SelectedSortType } from '../types/interface'; - -export const sortScopedState = atomFamily[], string>({ - key: 'sortScopedState', - default: [], -}); - -export const sortsByKeyScopedState = selectorFamily({ - key: 'sortsByKeyScopedState', - get: - (param: string) => - ({ get }) => - get(sortScopedState(param)).reduce>>( - (result, sort) => ({ ...result, [sort.key]: sort }), - {}, - ), -}); - -export const sortsOrderByScopedState = selectorFamily({ - key: 'sortsOrderByScopedState', - get: - (param: string) => - ({ get }) => - reduceSortsToOrderBy(get(sortScopedState(param))), -}); diff --git a/front/src/modules/ui/filter-n-sort/states/sortsOrderByScopedSelector.ts b/front/src/modules/ui/filter-n-sort/states/sortsOrderByScopedSelector.ts new file mode 100644 index 000000000..7ae4e80f1 --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/sortsOrderByScopedSelector.ts @@ -0,0 +1,13 @@ +import { selectorFamily } from 'recoil'; + +import { reduceSortsToOrderBy } from '../helpers'; + +import { sortsScopedState } from './sortsScopedState'; + +export const sortsOrderByScopedSelector = selectorFamily({ + key: 'sortsOrderByScopedSelector', + get: + (param: string) => + ({ get }) => + reduceSortsToOrderBy(get(sortsScopedState(param))), +}); diff --git a/front/src/modules/ui/filter-n-sort/states/sortsScopedState.ts b/front/src/modules/ui/filter-n-sort/states/sortsScopedState.ts new file mode 100644 index 000000000..968857aa3 --- /dev/null +++ b/front/src/modules/ui/filter-n-sort/states/sortsScopedState.ts @@ -0,0 +1,8 @@ +import { atomFamily } from 'recoil'; + +import type { SelectedSortType } from '../types/interface'; + +export const sortsScopedState = atomFamily[], string>({ + key: 'sortsScopedState', + default: [], +}); diff --git a/front/src/modules/ui/filter-n-sort/types/Filter.ts b/front/src/modules/ui/filter-n-sort/types/Filter.ts index a97353e2a..4cd8ad887 100644 --- a/front/src/modules/ui/filter-n-sort/types/Filter.ts +++ b/front/src/modules/ui/filter-n-sort/types/Filter.ts @@ -2,7 +2,7 @@ import { FilterOperand } from './FilterOperand'; import { FilterType } from './FilterType'; export type Filter = { - field: string; + key: string; type: FilterType; value: string; displayValue: string; diff --git a/front/src/modules/ui/filter-n-sort/types/FilterDefinition.ts b/front/src/modules/ui/filter-n-sort/types/FilterDefinition.ts index 089fba8e8..34e2751fe 100644 --- a/front/src/modules/ui/filter-n-sort/types/FilterDefinition.ts +++ b/front/src/modules/ui/filter-n-sort/types/FilterDefinition.ts @@ -1,7 +1,7 @@ import { FilterType } from './FilterType'; export type FilterDefinition = { - field: string; + key: string; label: string; icon: JSX.Element; type: FilterType; diff --git a/front/src/modules/ui/filter-n-sort/types/FilterDefinitionByEntity.ts b/front/src/modules/ui/filter-n-sort/types/FilterDefinitionByEntity.ts index f7af841bb..3449d7254 100644 --- a/front/src/modules/ui/filter-n-sort/types/FilterDefinitionByEntity.ts +++ b/front/src/modules/ui/filter-n-sort/types/FilterDefinitionByEntity.ts @@ -1,5 +1,5 @@ import { FilterDefinition } from './FilterDefinition'; export type FilterDefinitionByEntity = FilterDefinition & { - field: keyof T; + key: keyof T; }; diff --git a/front/src/modules/ui/filter-n-sort/types/FilterOperand.ts b/front/src/modules/ui/filter-n-sort/types/FilterOperand.ts index fd6c9ed00..9e9a893bc 100644 --- a/front/src/modules/ui/filter-n-sort/types/FilterOperand.ts +++ b/front/src/modules/ui/filter-n-sort/types/FilterOperand.ts @@ -1,7 +1 @@ -export type FilterOperand = - | 'contains' - | 'does-not-contain' - | 'greater-than' - | 'less-than' - | 'is' - | 'is-not'; +export { ViewFilterOperand as FilterOperand } from '~/generated/graphql'; diff --git a/front/src/modules/ui/filter-n-sort/utils/getOperandLabel.ts b/front/src/modules/ui/filter-n-sort/utils/getOperandLabel.ts index 97dd291cd..f1e0b05c9 100644 --- a/front/src/modules/ui/filter-n-sort/utils/getOperandLabel.ts +++ b/front/src/modules/ui/filter-n-sort/utils/getOperandLabel.ts @@ -2,17 +2,17 @@ import { FilterOperand } from '../types/FilterOperand'; export function getOperandLabel(operand: FilterOperand | null | undefined) { switch (operand) { - case 'contains': + case FilterOperand.Contains: return 'Contains'; - case 'does-not-contain': + case FilterOperand.DoesNotContain: return "Doesn't contain"; - case 'greater-than': + case FilterOperand.GreaterThan: return 'Greater than'; - case 'less-than': + case FilterOperand.LessThan: return 'Less than'; - case 'is': + case FilterOperand.Is: return 'Is'; - case 'is-not': + case FilterOperand.IsNot: return 'Is not'; default: return ''; @@ -22,15 +22,15 @@ export function getOperandLabelShort( operand: FilterOperand | null | undefined, ) { switch (operand) { - case 'is': - case 'contains': + case FilterOperand.Is: + case FilterOperand.Contains: return ': '; - case 'is-not': - case 'does-not-contain': + case FilterOperand.IsNot: + case FilterOperand.DoesNotContain: return ': Not'; - case 'greater-than': + case FilterOperand.GreaterThan: return '\u00A0> '; - case 'less-than': + case FilterOperand.LessThan: return '\u00A0< '; default: return ': '; diff --git a/front/src/modules/ui/filter-n-sort/utils/getOperandsForFilterType.ts b/front/src/modules/ui/filter-n-sort/utils/getOperandsForFilterType.ts index 2f87ab937..10ff6f8dd 100644 --- a/front/src/modules/ui/filter-n-sort/utils/getOperandsForFilterType.ts +++ b/front/src/modules/ui/filter-n-sort/utils/getOperandsForFilterType.ts @@ -6,12 +6,12 @@ export function getOperandsForFilterType( ): FilterOperand[] { switch (filterType) { case 'text': - return ['contains', 'does-not-contain']; + return [FilterOperand.Contains, FilterOperand.DoesNotContain]; case 'number': case 'date': - return ['greater-than', 'less-than']; + return [FilterOperand.GreaterThan, FilterOperand.LessThan]; case 'entity': - return ['is', 'is-not']; + return [FilterOperand.Is, FilterOperand.IsNot]; default: return []; } diff --git a/front/src/modules/ui/filter-n-sort/utils/turnFilterIntoWhereClause.ts b/front/src/modules/ui/filter-n-sort/utils/turnFilterIntoWhereClause.ts index 99a6d7f91..07c7ef0e8 100644 --- a/front/src/modules/ui/filter-n-sort/utils/turnFilterIntoWhereClause.ts +++ b/front/src/modules/ui/filter-n-sort/utils/turnFilterIntoWhereClause.ts @@ -1,21 +1,22 @@ import { QueryMode } from '~/generated/graphql'; import { Filter } from '../types/Filter'; +import { FilterOperand } from '../types/FilterOperand'; export function turnFilterIntoWhereClause(filter: Filter) { switch (filter.type) { case 'text': switch (filter.operand) { - case 'contains': + case FilterOperand.Contains: return { - [filter.field]: { + [filter.key]: { contains: filter.value, mode: QueryMode.Insensitive, }, }; - case 'does-not-contain': + case FilterOperand.DoesNotContain: return { - [filter.field]: { + [filter.key]: { not: { contains: filter.value, mode: QueryMode.Insensitive, @@ -29,15 +30,15 @@ export function turnFilterIntoWhereClause(filter: Filter) { } case 'number': switch (filter.operand) { - case 'greater-than': + case FilterOperand.GreaterThan: return { - [filter.field]: { + [filter.key]: { gte: parseFloat(filter.value), }, }; - case 'less-than': + case FilterOperand.LessThan: return { - [filter.field]: { + [filter.key]: { lte: parseFloat(filter.value), }, }; @@ -48,15 +49,15 @@ export function turnFilterIntoWhereClause(filter: Filter) { } case 'date': switch (filter.operand) { - case 'greater-than': + case FilterOperand.GreaterThan: return { - [filter.field]: { + [filter.key]: { gte: filter.value, }, }; - case 'less-than': + case FilterOperand.LessThan: return { - [filter.field]: { + [filter.key]: { lte: filter.value, }, }; @@ -67,15 +68,15 @@ export function turnFilterIntoWhereClause(filter: Filter) { } case 'entity': switch (filter.operand) { - case 'is': + case FilterOperand.Is: return { - [filter.field]: { + [filter.key]: { equals: filter.value, }, }; - case 'is-not': + case FilterOperand.IsNot: return { - [filter.field]: { + [filter.key]: { not: { equals: filter.value }, }, }; diff --git a/front/src/modules/ui/table/components/EntityTable.tsx b/front/src/modules/ui/table/components/EntityTable.tsx index 69cf81e16..c08da86b5 100644 --- a/front/src/modules/ui/table/components/EntityTable.tsx +++ b/front/src/modules/ui/table/components/EntityTable.tsx @@ -5,7 +5,7 @@ import type { ViewFieldDefinition, ViewFieldMetadata, } from '@/ui/editable-field/types/ViewField'; -import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface'; +import { SortType } from '@/ui/filter-n-sort/types/interface'; import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; @@ -97,8 +97,8 @@ type OwnProps = { viewIcon?: React.ReactNode; availableSorts?: Array>; onColumnsChange?: (columns: ViewFieldDefinition[]) => void; - onSortsUpdate?: (sorts: Array>) => void; onViewsChange?: (views: TableView[]) => void; + onViewSubmit?: () => void; onImport?: () => void; updateEntityMutation: any; }; @@ -107,8 +107,8 @@ export function EntityTable({ viewName, availableSorts, onColumnsChange, - onSortsUpdate, onViewsChange, + onViewSubmit, onImport, updateEntityMutation, }: OwnProps) { @@ -136,8 +136,8 @@ export function EntityTable({ viewName={viewName} availableSorts={availableSorts} onColumnsChange={onColumnsChange} - onSortsUpdate={onSortsUpdate} onViewsChange={onViewsChange} + onViewSubmit={onViewSubmit} onImport={onImport} /> diff --git a/front/src/modules/ui/table/options/components/TableUpdateViewButtonGroup.tsx b/front/src/modules/ui/table/options/components/TableUpdateViewButtonGroup.tsx new file mode 100644 index 000000000..c7bd8e928 --- /dev/null +++ b/front/src/modules/ui/table/options/components/TableUpdateViewButtonGroup.tsx @@ -0,0 +1,123 @@ +import { useCallback, useState } from 'react'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { useRecoilCallback, useSetRecoilState } from 'recoil'; +import { Key } from 'ts-key-enum'; + +import { Button, ButtonSize } from '@/ui/button/components/Button'; +import { ButtonGroup } from '@/ui/button/components/ButtonGroup'; +import { DropdownMenuItem } from '@/ui/dropdown/components/DropdownMenuItem'; +import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer'; +import { DropdownMenuContainer } from '@/ui/filter-n-sort/components/DropdownMenuContainer'; +import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState'; +import { savedFiltersScopedState } from '@/ui/filter-n-sort/states/savedFiltersScopedState'; +import { savedSortsScopedState } from '@/ui/filter-n-sort/states/savedSortsScopedState'; +import { sortsScopedState } from '@/ui/filter-n-sort/states/sortsScopedState'; +import { IconChevronDown, IconPlus } from '@/ui/icon'; +import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys'; +import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId'; +import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue'; + +import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext'; +import { + currentTableViewIdState, + tableViewEditModeState, +} from '../../states/tableViewsState'; + +const StyledContainer = styled.div` + display: inline-flex; + margin-right: ${({ theme }) => theme.spacing(2)}; + position: relative; +`; + +const StyledDropdownMenuContainer = styled(DropdownMenuContainer)` + z-index: 1; +`; + +type TableUpdateViewButtonGroupProps = { + onViewSubmit?: () => void; + HotkeyScope: string; +}; + +export const TableUpdateViewButtonGroup = ({ + onViewSubmit, + HotkeyScope, +}: TableUpdateViewButtonGroupProps) => { + const theme = useTheme(); + + const [isDropdownOpen, setIsDropdownOpen] = useState(false); + + const tableScopeId = useContextScopeId(TableRecoilScopeContext); + + const currentViewId = useRecoilScopedValue( + currentTableViewIdState, + TableRecoilScopeContext, + ); + const setViewEditMode = useSetRecoilState(tableViewEditModeState); + + const handleArrowDownButtonClick = useCallback(() => { + setIsDropdownOpen((previousIsOpen) => !previousIsOpen); + }, []); + + const handleCreateViewButtonClick = useCallback(() => { + setViewEditMode({ mode: 'create', viewId: undefined }); + setIsDropdownOpen(false); + }, [setViewEditMode]); + + const handleDropdownClose = useCallback(() => { + setIsDropdownOpen(false); + }, []); + + const handleViewSubmit = useRecoilCallback( + ({ set, snapshot }) => + async () => { + await Promise.resolve(onViewSubmit?.()); + + const selectedFilters = await snapshot.getPromise( + filtersScopedState(tableScopeId), + ); + set(savedFiltersScopedState(currentViewId), selectedFilters); + + const selectedSorts = await snapshot.getPromise( + sortsScopedState(tableScopeId), + ); + set(savedSortsScopedState(currentViewId), selectedSorts); + }, + [currentViewId, onViewSubmit], + ); + + useScopedHotkeys( + [Key.Enter, Key.Escape], + handleDropdownClose, + HotkeyScope, + [], + ); + + return ( + + +