feat: persist view filters and sorts on Update View button click (#1290)
* feat: add viewFilters table Closes #1121 * feat: add Update View button + Create View dropdown Closes #1124, #1289 * feat: add View Filter resolvers * feat: persist view filters and sorts on Update View button click Closes #1123 * refactor: code review - Rename recoil selectors - Rename filters `field` property to `key`
This commit is contained in:
@ -829,6 +829,13 @@ export type EnumPipelineProgressableTypeFilter = {
|
|||||||
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type EnumViewFilterOperandFilter = {
|
||||||
|
equals?: InputMaybe<ViewFilterOperand>;
|
||||||
|
in?: InputMaybe<Array<ViewFilterOperand>>;
|
||||||
|
not?: InputMaybe<NestedEnumViewFilterOperandFilter>;
|
||||||
|
notIn?: InputMaybe<Array<ViewFilterOperand>>;
|
||||||
|
};
|
||||||
|
|
||||||
export type EnumViewSortDirectionFilter = {
|
export type EnumViewSortDirectionFilter = {
|
||||||
equals?: InputMaybe<ViewSortDirection>;
|
equals?: InputMaybe<ViewSortDirection>;
|
||||||
in?: InputMaybe<Array<ViewSortDirection>>;
|
in?: InputMaybe<Array<ViewSortDirection>>;
|
||||||
@ -969,6 +976,7 @@ export type Mutation = {
|
|||||||
createManyPerson: AffectedRows;
|
createManyPerson: AffectedRows;
|
||||||
createManyView: AffectedRows;
|
createManyView: AffectedRows;
|
||||||
createManyViewField: AffectedRows;
|
createManyViewField: AffectedRows;
|
||||||
|
createManyViewFilter: AffectedRows;
|
||||||
createManyViewSort: AffectedRows;
|
createManyViewSort: AffectedRows;
|
||||||
createOneActivity: Activity;
|
createOneActivity: Activity;
|
||||||
createOneComment: Comment;
|
createOneComment: Comment;
|
||||||
@ -983,6 +991,7 @@ export type Mutation = {
|
|||||||
deleteManyPerson: AffectedRows;
|
deleteManyPerson: AffectedRows;
|
||||||
deleteManyPipelineProgress: AffectedRows;
|
deleteManyPipelineProgress: AffectedRows;
|
||||||
deleteManyView: AffectedRows;
|
deleteManyView: AffectedRows;
|
||||||
|
deleteManyViewFilter: AffectedRows;
|
||||||
deleteManyViewSort: AffectedRows;
|
deleteManyViewSort: AffectedRows;
|
||||||
deleteUserAccount: User;
|
deleteUserAccount: User;
|
||||||
deleteWorkspaceMember: WorkspaceMember;
|
deleteWorkspaceMember: WorkspaceMember;
|
||||||
@ -996,6 +1005,7 @@ export type Mutation = {
|
|||||||
updateOnePipelineStage?: Maybe<PipelineStage>;
|
updateOnePipelineStage?: Maybe<PipelineStage>;
|
||||||
updateOneView: View;
|
updateOneView: View;
|
||||||
updateOneViewField: ViewField;
|
updateOneViewField: ViewField;
|
||||||
|
updateOneViewFilter: ViewFilter;
|
||||||
updateOneViewSort: ViewSort;
|
updateOneViewSort: ViewSort;
|
||||||
updateUser: User;
|
updateUser: User;
|
||||||
updateWorkspace: Workspace;
|
updateWorkspace: Workspace;
|
||||||
@ -1060,6 +1070,12 @@ export type MutationCreateManyViewFieldArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationCreateManyViewFilterArgs = {
|
||||||
|
data: Array<ViewFilterCreateManyInput>;
|
||||||
|
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateManyViewSortArgs = {
|
export type MutationCreateManyViewSortArgs = {
|
||||||
data: Array<ViewSortCreateManyInput>;
|
data: Array<ViewSortCreateManyInput>;
|
||||||
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
||||||
@ -1126,6 +1142,11 @@ export type MutationDeleteManyViewArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationDeleteManyViewFilterArgs = {
|
||||||
|
where?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationDeleteManyViewSortArgs = {
|
export type MutationDeleteManyViewSortArgs = {
|
||||||
where?: InputMaybe<ViewSortWhereInput>;
|
where?: InputMaybe<ViewSortWhereInput>;
|
||||||
};
|
};
|
||||||
@ -1195,6 +1216,12 @@ export type MutationUpdateOneViewFieldArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationUpdateOneViewFilterArgs = {
|
||||||
|
data: ViewFilterUpdateInput;
|
||||||
|
where: ViewFilterWhereUniqueInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationUpdateOneViewSortArgs = {
|
export type MutationUpdateOneViewSortArgs = {
|
||||||
data: ViewSortUpdateInput;
|
data: ViewSortUpdateInput;
|
||||||
where: ViewSortWhereUniqueInput;
|
where: ViewSortWhereUniqueInput;
|
||||||
@ -1305,6 +1332,13 @@ export type NestedEnumPipelineProgressableTypeFilter = {
|
|||||||
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NestedEnumViewFilterOperandFilter = {
|
||||||
|
equals?: InputMaybe<ViewFilterOperand>;
|
||||||
|
in?: InputMaybe<Array<ViewFilterOperand>>;
|
||||||
|
not?: InputMaybe<NestedEnumViewFilterOperandFilter>;
|
||||||
|
notIn?: InputMaybe<Array<ViewFilterOperand>>;
|
||||||
|
};
|
||||||
|
|
||||||
export type NestedEnumViewSortDirectionFilter = {
|
export type NestedEnumViewSortDirectionFilter = {
|
||||||
equals?: InputMaybe<ViewSortDirection>;
|
equals?: InputMaybe<ViewSortDirection>;
|
||||||
in?: InputMaybe<Array<ViewSortDirection>>;
|
in?: InputMaybe<Array<ViewSortDirection>>;
|
||||||
@ -1930,6 +1964,7 @@ export type Query = {
|
|||||||
findManyUser: Array<User>;
|
findManyUser: Array<User>;
|
||||||
findManyView: Array<View>;
|
findManyView: Array<View>;
|
||||||
findManyViewField: Array<ViewField>;
|
findManyViewField: Array<ViewField>;
|
||||||
|
findManyViewFilter: Array<ViewFilter>;
|
||||||
findManyViewSort: Array<ViewSort>;
|
findManyViewSort: Array<ViewSort>;
|
||||||
findManyWorkspaceMember: Array<WorkspaceMember>;
|
findManyWorkspaceMember: Array<WorkspaceMember>;
|
||||||
findUniqueCompany: Company;
|
findUniqueCompany: Company;
|
||||||
@ -2038,6 +2073,16 @@ export type QueryFindManyViewFieldArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type QueryFindManyViewFilterArgs = {
|
||||||
|
cursor?: InputMaybe<ViewFilterWhereUniqueInput>;
|
||||||
|
distinct?: InputMaybe<Array<ViewFilterScalarFieldEnum>>;
|
||||||
|
orderBy?: InputMaybe<Array<ViewFilterOrderByWithRelationInput>>;
|
||||||
|
skip?: InputMaybe<Scalars['Int']>;
|
||||||
|
take?: InputMaybe<Scalars['Int']>;
|
||||||
|
where?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type QueryFindManyViewSortArgs = {
|
export type QueryFindManyViewSortArgs = {
|
||||||
cursor?: InputMaybe<ViewSortWhereUniqueInput>;
|
cursor?: InputMaybe<ViewSortWhereUniqueInput>;
|
||||||
distinct?: InputMaybe<Array<ViewSortScalarFieldEnum>>;
|
distinct?: InputMaybe<Array<ViewSortScalarFieldEnum>>;
|
||||||
@ -2349,6 +2394,7 @@ export type Verify = {
|
|||||||
export type View = {
|
export type View = {
|
||||||
__typename?: 'View';
|
__typename?: 'View';
|
||||||
fields?: Maybe<Array<ViewField>>;
|
fields?: Maybe<Array<ViewField>>;
|
||||||
|
filters?: Maybe<Array<ViewFilter>>;
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
objectId: Scalars['String'];
|
objectId: Scalars['String'];
|
||||||
@ -2478,8 +2524,111 @@ export type ViewFieldWorkspaceIdViewIdObjectNameFieldNameCompoundUniqueInput = {
|
|||||||
viewId: Scalars['String'];
|
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<ViewFilterWhereInput>;
|
||||||
|
none?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
some?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum ViewFilterOperand {
|
||||||
|
Contains = 'Contains',
|
||||||
|
DoesNotContain = 'DoesNotContain',
|
||||||
|
GreaterThan = 'GreaterThan',
|
||||||
|
Is = 'Is',
|
||||||
|
IsNot = 'IsNot',
|
||||||
|
LessThan = 'LessThan'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ViewFilterOrderByRelationAggregateInput = {
|
||||||
|
_count?: InputMaybe<SortOrder>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterOrderByWithRelationInput = {
|
||||||
|
displayValue?: InputMaybe<SortOrder>;
|
||||||
|
key?: InputMaybe<SortOrder>;
|
||||||
|
name?: InputMaybe<SortOrder>;
|
||||||
|
operand?: InputMaybe<SortOrder>;
|
||||||
|
value?: InputMaybe<SortOrder>;
|
||||||
|
view?: InputMaybe<ViewOrderByWithRelationInput>;
|
||||||
|
viewId?: InputMaybe<SortOrder>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum ViewFilterScalarFieldEnum {
|
||||||
|
DisplayValue = 'displayValue',
|
||||||
|
Key = 'key',
|
||||||
|
Name = 'name',
|
||||||
|
Operand = 'operand',
|
||||||
|
Value = 'value',
|
||||||
|
ViewId = 'viewId',
|
||||||
|
WorkspaceId = 'workspaceId'
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ViewFilterUpdateInput = {
|
||||||
|
displayValue?: InputMaybe<Scalars['String']>;
|
||||||
|
key?: InputMaybe<Scalars['String']>;
|
||||||
|
name?: InputMaybe<Scalars['String']>;
|
||||||
|
operand?: InputMaybe<ViewFilterOperand>;
|
||||||
|
value?: InputMaybe<Scalars['String']>;
|
||||||
|
view?: InputMaybe<ViewUpdateOneRequiredWithoutFiltersNestedInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterUpdateManyWithoutViewNestedInput = {
|
||||||
|
connect?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
disconnect?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
set?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterUpdateManyWithoutWorkspaceNestedInput = {
|
||||||
|
connect?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
disconnect?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
set?: InputMaybe<Array<ViewFilterWhereUniqueInput>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterViewIdKeyCompoundUniqueInput = {
|
||||||
|
key: Scalars['String'];
|
||||||
|
viewId: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterWhereInput = {
|
||||||
|
AND?: InputMaybe<Array<ViewFilterWhereInput>>;
|
||||||
|
NOT?: InputMaybe<Array<ViewFilterWhereInput>>;
|
||||||
|
OR?: InputMaybe<Array<ViewFilterWhereInput>>;
|
||||||
|
displayValue?: InputMaybe<StringFilter>;
|
||||||
|
key?: InputMaybe<StringFilter>;
|
||||||
|
name?: InputMaybe<StringFilter>;
|
||||||
|
operand?: InputMaybe<EnumViewFilterOperandFilter>;
|
||||||
|
value?: InputMaybe<StringFilter>;
|
||||||
|
view?: InputMaybe<ViewRelationFilter>;
|
||||||
|
viewId?: InputMaybe<StringFilter>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ViewFilterWhereUniqueInput = {
|
||||||
|
viewId_key?: InputMaybe<ViewFilterViewIdKeyCompoundUniqueInput>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ViewOrderByWithRelationInput = {
|
export type ViewOrderByWithRelationInput = {
|
||||||
fields?: InputMaybe<ViewFieldOrderByRelationAggregateInput>;
|
fields?: InputMaybe<ViewFieldOrderByRelationAggregateInput>;
|
||||||
|
filters?: InputMaybe<ViewFilterOrderByRelationAggregateInput>;
|
||||||
id?: InputMaybe<SortOrder>;
|
id?: InputMaybe<SortOrder>;
|
||||||
name?: InputMaybe<SortOrder>;
|
name?: InputMaybe<SortOrder>;
|
||||||
objectId?: InputMaybe<SortOrder>;
|
objectId?: InputMaybe<SortOrder>;
|
||||||
@ -2593,6 +2742,7 @@ export enum ViewType {
|
|||||||
|
|
||||||
export type ViewUpdateInput = {
|
export type ViewUpdateInput = {
|
||||||
fields?: InputMaybe<ViewFieldUpdateManyWithoutViewNestedInput>;
|
fields?: InputMaybe<ViewFieldUpdateManyWithoutViewNestedInput>;
|
||||||
|
filters?: InputMaybe<ViewFilterUpdateManyWithoutViewNestedInput>;
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
name?: InputMaybe<Scalars['String']>;
|
name?: InputMaybe<Scalars['String']>;
|
||||||
objectId?: InputMaybe<Scalars['String']>;
|
objectId?: InputMaybe<Scalars['String']>;
|
||||||
@ -2606,6 +2756,10 @@ export type ViewUpdateManyWithoutWorkspaceNestedInput = {
|
|||||||
set?: InputMaybe<Array<ViewWhereUniqueInput>>;
|
set?: InputMaybe<Array<ViewWhereUniqueInput>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ViewUpdateOneRequiredWithoutFiltersNestedInput = {
|
||||||
|
connect?: InputMaybe<ViewWhereUniqueInput>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ViewUpdateOneRequiredWithoutSortsNestedInput = {
|
export type ViewUpdateOneRequiredWithoutSortsNestedInput = {
|
||||||
connect?: InputMaybe<ViewWhereUniqueInput>;
|
connect?: InputMaybe<ViewWhereUniqueInput>;
|
||||||
};
|
};
|
||||||
@ -2620,6 +2774,7 @@ export type ViewWhereInput = {
|
|||||||
NOT?: InputMaybe<Array<ViewWhereInput>>;
|
NOT?: InputMaybe<Array<ViewWhereInput>>;
|
||||||
OR?: InputMaybe<Array<ViewWhereInput>>;
|
OR?: InputMaybe<Array<ViewWhereInput>>;
|
||||||
fields?: InputMaybe<ViewFieldListRelationFilter>;
|
fields?: InputMaybe<ViewFieldListRelationFilter>;
|
||||||
|
filters?: InputMaybe<ViewFilterListRelationFilter>;
|
||||||
id?: InputMaybe<StringFilter>;
|
id?: InputMaybe<StringFilter>;
|
||||||
name?: InputMaybe<StringFilter>;
|
name?: InputMaybe<StringFilter>;
|
||||||
objectId?: InputMaybe<StringFilter>;
|
objectId?: InputMaybe<StringFilter>;
|
||||||
@ -2657,6 +2812,7 @@ export type Workspace = {
|
|||||||
pipelines?: Maybe<Array<Pipeline>>;
|
pipelines?: Maybe<Array<Pipeline>>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
viewFields?: Maybe<Array<ViewField>>;
|
viewFields?: Maybe<Array<ViewField>>;
|
||||||
|
viewFilters?: Maybe<Array<ViewFilter>>;
|
||||||
viewSorts?: Maybe<Array<ViewSort>>;
|
viewSorts?: Maybe<Array<ViewSort>>;
|
||||||
views?: Maybe<Array<View>>;
|
views?: Maybe<Array<View>>;
|
||||||
workspaceMember?: Maybe<Array<WorkspaceMember>>;
|
workspaceMember?: Maybe<Array<WorkspaceMember>>;
|
||||||
@ -2741,6 +2897,7 @@ export type WorkspaceUpdateInput = {
|
|||||||
pipelines?: InputMaybe<PipelineUpdateManyWithoutWorkspaceNestedInput>;
|
pipelines?: InputMaybe<PipelineUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
viewFields?: InputMaybe<ViewFieldUpdateManyWithoutWorkspaceNestedInput>;
|
viewFields?: InputMaybe<ViewFieldUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
|
viewFilters?: InputMaybe<ViewFilterUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
viewSorts?: InputMaybe<ViewSortUpdateManyWithoutWorkspaceNestedInput>;
|
viewSorts?: InputMaybe<ViewSortUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
views?: InputMaybe<ViewUpdateManyWithoutWorkspaceNestedInput>;
|
views?: InputMaybe<ViewUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
workspaceMember?: InputMaybe<WorkspaceMemberUpdateManyWithoutWorkspaceNestedInput>;
|
workspaceMember?: InputMaybe<WorkspaceMemberUpdateManyWithoutWorkspaceNestedInput>;
|
||||||
@ -2838,7 +2995,7 @@ export type CreateEventMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type CreateEventMutation = { __typename?: 'Mutation', createEvent: { __typename?: 'Analytics', success: boolean } };
|
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<{
|
export type ChallengeMutationVariables = Exact<{
|
||||||
email: Scalars['String'];
|
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<{
|
export type RenewTokenMutationVariables = Exact<{
|
||||||
refreshToken: Scalars['String'];
|
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<{
|
export type CheckUserExistsQueryVariables = Exact<{
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
@ -3216,6 +3373,13 @@ export type CreateViewFieldsMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type CreateViewFieldsMutation = { __typename?: 'Mutation', createManyViewField: { __typename?: 'AffectedRows', count: number } };
|
export type CreateViewFieldsMutation = { __typename?: 'Mutation', createManyViewField: { __typename?: 'AffectedRows', count: number } };
|
||||||
|
|
||||||
|
export type CreateViewFiltersMutationVariables = Exact<{
|
||||||
|
data: Array<ViewFilterCreateManyInput> | ViewFilterCreateManyInput;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type CreateViewFiltersMutation = { __typename?: 'Mutation', createManyViewFilter: { __typename?: 'AffectedRows', count: number } };
|
||||||
|
|
||||||
export type CreateViewSortsMutationVariables = Exact<{
|
export type CreateViewSortsMutationVariables = Exact<{
|
||||||
data: Array<ViewSortCreateManyInput> | ViewSortCreateManyInput;
|
data: Array<ViewSortCreateManyInput> | ViewSortCreateManyInput;
|
||||||
}>;
|
}>;
|
||||||
@ -3230,7 +3394,6 @@ export type CreateViewsMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type CreateViewsMutation = { __typename?: 'Mutation', createManyView: { __typename?: 'AffectedRows', count: number } };
|
export type CreateViewsMutation = { __typename?: 'Mutation', createManyView: { __typename?: 'AffectedRows', count: number } };
|
||||||
|
|
||||||
|
|
||||||
export type DeleteViewsMutationVariables = Exact<{
|
export type DeleteViewsMutationVariables = Exact<{
|
||||||
where: ViewWhereInput;
|
where: ViewWhereInput;
|
||||||
}>;
|
}>;
|
||||||
@ -3238,6 +3401,12 @@ export type DeleteViewsMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type DeleteViewsMutation = { __typename?: 'Mutation', deleteManyView: { __typename?: 'AffectedRows', count: number } };
|
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<{
|
export type DeleteViewSortsMutationVariables = Exact<{
|
||||||
where: ViewSortWhereInput;
|
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 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<{
|
export type UpdateViewSortMutationVariables = Exact<{
|
||||||
data: ViewSortUpdateInput;
|
data: ViewSortUpdateInput;
|
||||||
where: ViewSortWhereUniqueInput;
|
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 GetViewFieldsQuery = { __typename?: 'Query', viewFields: Array<{ __typename?: 'ViewField', id: string, fieldName: string, isVisible: boolean, sizeInPx: number, index: number }> };
|
||||||
|
|
||||||
|
export type GetViewFiltersQueryVariables = Exact<{
|
||||||
|
where?: InputMaybe<ViewFilterWhereInput>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type GetViewFiltersQuery = { __typename?: 'Query', viewFilters: Array<{ __typename?: 'ViewFilter', displayValue: string, key: string, name: string, operand: ViewFilterOperand, value: string }> };
|
||||||
|
|
||||||
export type GetViewSortsQueryVariables = Exact<{
|
export type GetViewSortsQueryVariables = Exact<{
|
||||||
where?: InputMaybe<ViewSortWhereInput>;
|
where?: InputMaybe<ViewSortWhereInput>;
|
||||||
}>;
|
}>;
|
||||||
@ -5934,6 +6118,39 @@ export function useCreateViewFieldsMutation(baseOptions?: Apollo.MutationHookOpt
|
|||||||
export type CreateViewFieldsMutationHookResult = ReturnType<typeof useCreateViewFieldsMutation>;
|
export type CreateViewFieldsMutationHookResult = ReturnType<typeof useCreateViewFieldsMutation>;
|
||||||
export type CreateViewFieldsMutationResult = Apollo.MutationResult<CreateViewFieldsMutation>;
|
export type CreateViewFieldsMutationResult = Apollo.MutationResult<CreateViewFieldsMutation>;
|
||||||
export type CreateViewFieldsMutationOptions = Apollo.BaseMutationOptions<CreateViewFieldsMutation, CreateViewFieldsMutationVariables>;
|
export type CreateViewFieldsMutationOptions = Apollo.BaseMutationOptions<CreateViewFieldsMutation, CreateViewFieldsMutationVariables>;
|
||||||
|
export const CreateViewFiltersDocument = gql`
|
||||||
|
mutation CreateViewFilters($data: [ViewFilterCreateManyInput!]!) {
|
||||||
|
createManyViewFilter(data: $data) {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type CreateViewFiltersMutationFn = Apollo.MutationFunction<CreateViewFiltersMutation, CreateViewFiltersMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __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<CreateViewFiltersMutation, CreateViewFiltersMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<CreateViewFiltersMutation, CreateViewFiltersMutationVariables>(CreateViewFiltersDocument, options);
|
||||||
|
}
|
||||||
|
export type CreateViewFiltersMutationHookResult = ReturnType<typeof useCreateViewFiltersMutation>;
|
||||||
|
export type CreateViewFiltersMutationResult = Apollo.MutationResult<CreateViewFiltersMutation>;
|
||||||
|
export type CreateViewFiltersMutationOptions = Apollo.BaseMutationOptions<CreateViewFiltersMutation, CreateViewFiltersMutationVariables>;
|
||||||
export const CreateViewSortsDocument = gql`
|
export const CreateViewSortsDocument = gql`
|
||||||
mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) {
|
mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) {
|
||||||
createManyViewSort(data: $data) {
|
createManyViewSort(data: $data) {
|
||||||
@ -6000,7 +6217,6 @@ export function useCreateViewsMutation(baseOptions?: Apollo.MutationHookOptions<
|
|||||||
export type CreateViewsMutationHookResult = ReturnType<typeof useCreateViewsMutation>;
|
export type CreateViewsMutationHookResult = ReturnType<typeof useCreateViewsMutation>;
|
||||||
export type CreateViewsMutationResult = Apollo.MutationResult<CreateViewsMutation>;
|
export type CreateViewsMutationResult = Apollo.MutationResult<CreateViewsMutation>;
|
||||||
export type CreateViewsMutationOptions = Apollo.BaseMutationOptions<CreateViewsMutation, CreateViewsMutationVariables>;
|
export type CreateViewsMutationOptions = Apollo.BaseMutationOptions<CreateViewsMutation, CreateViewsMutationVariables>;
|
||||||
|
|
||||||
export const DeleteViewsDocument = gql`
|
export const DeleteViewsDocument = gql`
|
||||||
mutation DeleteViews($where: ViewWhereInput!) {
|
mutation DeleteViews($where: ViewWhereInput!) {
|
||||||
deleteManyView(where: $where) {
|
deleteManyView(where: $where) {
|
||||||
@ -6034,7 +6250,39 @@ export function useDeleteViewsMutation(baseOptions?: Apollo.MutationHookOptions<
|
|||||||
export type DeleteViewsMutationHookResult = ReturnType<typeof useDeleteViewsMutation>;
|
export type DeleteViewsMutationHookResult = ReturnType<typeof useDeleteViewsMutation>;
|
||||||
export type DeleteViewsMutationResult = Apollo.MutationResult<DeleteViewsMutation>;
|
export type DeleteViewsMutationResult = Apollo.MutationResult<DeleteViewsMutation>;
|
||||||
export type DeleteViewsMutationOptions = Apollo.BaseMutationOptions<DeleteViewsMutation, DeleteViewsMutationVariables>;
|
export type DeleteViewsMutationOptions = Apollo.BaseMutationOptions<DeleteViewsMutation, DeleteViewsMutationVariables>;
|
||||||
|
export const DeleteViewFiltersDocument = gql`
|
||||||
|
mutation DeleteViewFilters($where: ViewFilterWhereInput!) {
|
||||||
|
deleteManyViewFilter(where: $where) {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type DeleteViewFiltersMutationFn = Apollo.MutationFunction<DeleteViewFiltersMutation, DeleteViewFiltersMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __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<DeleteViewFiltersMutation, DeleteViewFiltersMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<DeleteViewFiltersMutation, DeleteViewFiltersMutationVariables>(DeleteViewFiltersDocument, options);
|
||||||
|
}
|
||||||
|
export type DeleteViewFiltersMutationHookResult = ReturnType<typeof useDeleteViewFiltersMutation>;
|
||||||
|
export type DeleteViewFiltersMutationResult = Apollo.MutationResult<DeleteViewFiltersMutation>;
|
||||||
|
export type DeleteViewFiltersMutationOptions = Apollo.BaseMutationOptions<DeleteViewFiltersMutation, DeleteViewFiltersMutationVariables>;
|
||||||
export const DeleteViewSortsDocument = gql`
|
export const DeleteViewSortsDocument = gql`
|
||||||
mutation DeleteViewSorts($where: ViewSortWhereInput!) {
|
mutation DeleteViewSorts($where: ViewSortWhereInput!) {
|
||||||
deleteManyViewSort(where: $where) {
|
deleteManyViewSort(where: $where) {
|
||||||
@ -6141,6 +6389,44 @@ export function useUpdateViewFieldMutation(baseOptions?: Apollo.MutationHookOpti
|
|||||||
export type UpdateViewFieldMutationHookResult = ReturnType<typeof useUpdateViewFieldMutation>;
|
export type UpdateViewFieldMutationHookResult = ReturnType<typeof useUpdateViewFieldMutation>;
|
||||||
export type UpdateViewFieldMutationResult = Apollo.MutationResult<UpdateViewFieldMutation>;
|
export type UpdateViewFieldMutationResult = Apollo.MutationResult<UpdateViewFieldMutation>;
|
||||||
export type UpdateViewFieldMutationOptions = Apollo.BaseMutationOptions<UpdateViewFieldMutation, UpdateViewFieldMutationVariables>;
|
export type UpdateViewFieldMutationOptions = Apollo.BaseMutationOptions<UpdateViewFieldMutation, UpdateViewFieldMutationVariables>;
|
||||||
|
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<UpdateViewFilterMutation, UpdateViewFilterMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __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<UpdateViewFilterMutation, UpdateViewFilterMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<UpdateViewFilterMutation, UpdateViewFilterMutationVariables>(UpdateViewFilterDocument, options);
|
||||||
|
}
|
||||||
|
export type UpdateViewFilterMutationHookResult = ReturnType<typeof useUpdateViewFilterMutation>;
|
||||||
|
export type UpdateViewFilterMutationResult = Apollo.MutationResult<UpdateViewFilterMutation>;
|
||||||
|
export type UpdateViewFilterMutationOptions = Apollo.BaseMutationOptions<UpdateViewFilterMutation, UpdateViewFilterMutationVariables>;
|
||||||
export const UpdateViewSortDocument = gql`
|
export const UpdateViewSortDocument = gql`
|
||||||
mutation UpdateViewSort($data: ViewSortUpdateInput!, $where: ViewSortWhereUniqueInput!) {
|
mutation UpdateViewSort($data: ViewSortUpdateInput!, $where: ViewSortWhereUniqueInput!) {
|
||||||
viewSort: updateOneViewSort(data: $data, where: $where) {
|
viewSort: updateOneViewSort(data: $data, where: $where) {
|
||||||
@ -6217,6 +6503,45 @@ export function useGetViewFieldsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpti
|
|||||||
export type GetViewFieldsQueryHookResult = ReturnType<typeof useGetViewFieldsQuery>;
|
export type GetViewFieldsQueryHookResult = ReturnType<typeof useGetViewFieldsQuery>;
|
||||||
export type GetViewFieldsLazyQueryHookResult = ReturnType<typeof useGetViewFieldsLazyQuery>;
|
export type GetViewFieldsLazyQueryHookResult = ReturnType<typeof useGetViewFieldsLazyQuery>;
|
||||||
export type GetViewFieldsQueryResult = Apollo.QueryResult<GetViewFieldsQuery, GetViewFieldsQueryVariables>;
|
export type GetViewFieldsQueryResult = Apollo.QueryResult<GetViewFieldsQuery, GetViewFieldsQueryVariables>;
|
||||||
|
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<GetViewFiltersQuery, GetViewFiltersQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<GetViewFiltersQuery, GetViewFiltersQueryVariables>(GetViewFiltersDocument, options);
|
||||||
|
}
|
||||||
|
export function useGetViewFiltersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetViewFiltersQuery, GetViewFiltersQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<GetViewFiltersQuery, GetViewFiltersQueryVariables>(GetViewFiltersDocument, options);
|
||||||
|
}
|
||||||
|
export type GetViewFiltersQueryHookResult = ReturnType<typeof useGetViewFiltersQuery>;
|
||||||
|
export type GetViewFiltersLazyQueryHookResult = ReturnType<typeof useGetViewFiltersLazyQuery>;
|
||||||
|
export type GetViewFiltersQueryResult = Apollo.QueryResult<GetViewFiltersQuery, GetViewFiltersQueryVariables>;
|
||||||
export const GetViewSortsDocument = gql`
|
export const GetViewSortsDocument = gql`
|
||||||
query GetViewSorts($where: ViewSortWhereInput) {
|
query GetViewSorts($where: ViewSortWhereInput) {
|
||||||
viewSorts: findManyViewSort(where: $where) {
|
viewSorts: findManyViewSort(where: $where) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
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 { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
|
||||||
import { activeTabIdScopedState } from '@/ui/tab/states/activeTabIdScopedState';
|
import { activeTabIdScopedState } from '@/ui/tab/states/activeTabIdScopedState';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
@ -37,10 +38,10 @@ export function useTasks() {
|
|||||||
if (currentUser && !filters.length) {
|
if (currentUser && !filters.length) {
|
||||||
setFilters([
|
setFilters([
|
||||||
{
|
{
|
||||||
field: 'assigneeId',
|
key: 'assigneeId',
|
||||||
type: 'entity',
|
type: 'entity',
|
||||||
value: currentUser.id,
|
value: currentUser.id,
|
||||||
operand: 'is',
|
operand: FilterOperand.Is,
|
||||||
displayValue: currentUser.displayName,
|
displayValue: currentUser.displayName,
|
||||||
displayAvatarUrl: currentUser.avatarUrl ?? undefined,
|
displayAvatarUrl: currentUser.avatarUrl ?? undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { companyViewFields } from '@/companies/constants/companyViewFields';
|
import { companyViewFields } from '@/companies/constants/companyViewFields';
|
||||||
import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries';
|
import { useCompanyTableActionBarEntries } from '@/companies/hooks/useCompanyTableActionBarEntries';
|
||||||
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
import { useCompanyTableContextMenuEntries } from '@/companies/hooks/useCompanyTableContextMenuEntries';
|
||||||
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
import { useSpreadsheetCompanyImport } from '@/companies/hooks/useSpreadsheetCompanyImport';
|
||||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
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 { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
|
||||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
||||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
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 { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { useTableViewFields } from '@/views/hooks/useTableViewFields';
|
import { useTableViewFields } from '@/views/hooks/useTableViewFields';
|
||||||
import { useTableViews } from '@/views/hooks/useTableViews';
|
import { useTableViews } from '@/views/hooks/useTableViews';
|
||||||
|
import { useViewFilters } from '@/views/hooks/useViewFilters';
|
||||||
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
||||||
import {
|
import {
|
||||||
SortOrder,
|
SortOrder,
|
||||||
@ -26,12 +26,8 @@ import { companiesFilters } from '~/pages/companies/companies-filters';
|
|||||||
import { availableSorts } from '~/pages/companies/companies-sorts';
|
import { availableSorts } from '~/pages/companies/companies-sorts';
|
||||||
|
|
||||||
export function CompanyTable() {
|
export function CompanyTable() {
|
||||||
const currentViewId = useRecoilScopedValue(
|
|
||||||
currentTableViewIdState,
|
|
||||||
TableRecoilScopeContext,
|
|
||||||
);
|
|
||||||
const orderBy = useRecoilScopedValue(
|
const orderBy = useRecoilScopedValue(
|
||||||
sortsOrderByScopedState,
|
sortsOrderByScopedSelector,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
);
|
);
|
||||||
const [updateEntityMutation] = useUpdateOneCompanyMutation();
|
const [updateEntityMutation] = useUpdateOneCompanyMutation();
|
||||||
@ -44,7 +40,10 @@ export function CompanyTable() {
|
|||||||
viewFieldDefinitions: companyViewFields,
|
viewFieldDefinitions: companyViewFields,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { handleSortsChange } = useViewSorts({ availableSorts });
|
const { persistFilters } = useViewFilters({
|
||||||
|
availableFilters: companiesFilters,
|
||||||
|
});
|
||||||
|
const { persistSorts } = useViewSorts({ availableSorts });
|
||||||
const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
|
const { openCompanySpreadsheetImport } = useSpreadsheetCompanyImport();
|
||||||
|
|
||||||
const filters = useRecoilScopedValue(
|
const filters = useRecoilScopedValue(
|
||||||
@ -59,6 +58,11 @@ export function CompanyTable() {
|
|||||||
const { setContextMenuEntries } = useCompanyTableContextMenuEntries();
|
const { setContextMenuEntries } = useCompanyTableContextMenuEntries();
|
||||||
const { setActionBarEntries } = useCompanyTableActionBarEntries();
|
const { setActionBarEntries } = useCompanyTableActionBarEntries();
|
||||||
|
|
||||||
|
const handleViewSubmit = useCallback(async () => {
|
||||||
|
await persistFilters();
|
||||||
|
await persistSorts();
|
||||||
|
}, [persistFilters, persistSorts]);
|
||||||
|
|
||||||
function handleImport() {
|
function handleImport() {
|
||||||
openCompanySpreadsheetImport();
|
openCompanySpreadsheetImport();
|
||||||
}
|
}
|
||||||
@ -68,15 +72,7 @@ export function CompanyTable() {
|
|||||||
<GenericEntityTableData
|
<GenericEntityTableData
|
||||||
getRequestResultKey="companies"
|
getRequestResultKey="companies"
|
||||||
useGetRequest={useGetCompaniesQuery}
|
useGetRequest={useGetCompaniesQuery}
|
||||||
orderBy={
|
orderBy={orderBy.length ? orderBy : [{ createdAt: SortOrder.Desc }]}
|
||||||
orderBy.length
|
|
||||||
? orderBy
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
createdAt: SortOrder.Desc,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
whereFilters={whereFilters}
|
whereFilters={whereFilters}
|
||||||
filterDefinitionArray={companiesFilters}
|
filterDefinitionArray={companiesFilters}
|
||||||
setContextMenuEntries={setContextMenuEntries}
|
setContextMenuEntries={setContextMenuEntries}
|
||||||
@ -86,8 +82,8 @@ export function CompanyTable() {
|
|||||||
viewName="All Companies"
|
viewName="All Companies"
|
||||||
availableSorts={availableSorts}
|
availableSorts={availableSorts}
|
||||||
onColumnsChange={handleColumnsChange}
|
onColumnsChange={handleColumnsChange}
|
||||||
onSortsUpdate={currentViewId ? handleSortsChange : undefined}
|
|
||||||
onViewsChange={handleViewsChange}
|
onViewsChange={handleViewsChange}
|
||||||
|
onViewSubmit={handleViewSubmit}
|
||||||
onImport={handleImport}
|
onImport={handleImport}
|
||||||
updateEntityMutation={({
|
updateEntityMutation={({
|
||||||
variables,
|
variables,
|
||||||
|
|||||||
@ -1,20 +1,20 @@
|
|||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { peopleViewFields } from '@/people/constants/peopleViewFields';
|
import { peopleViewFields } from '@/people/constants/peopleViewFields';
|
||||||
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePeopleTableContextMenuEntries';
|
import { usePersonTableContextMenuEntries } from '@/people/hooks/usePeopleTableContextMenuEntries';
|
||||||
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
|
import { usePersonTableActionBarEntries } from '@/people/hooks/usePersonTableActionBarEntries';
|
||||||
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
import { useSpreadsheetPersonImport } from '@/people/hooks/useSpreadsheetPersonImport';
|
||||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
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 { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
|
||||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
||||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||||
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
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 { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
import { useTableViewFields } from '@/views/hooks/useTableViewFields';
|
import { useTableViewFields } from '@/views/hooks/useTableViewFields';
|
||||||
import { useTableViews } from '@/views/hooks/useTableViews';
|
import { useTableViews } from '@/views/hooks/useTableViews';
|
||||||
|
import { useViewFilters } from '@/views/hooks/useViewFilters';
|
||||||
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
||||||
import {
|
import {
|
||||||
SortOrder,
|
SortOrder,
|
||||||
@ -26,12 +26,8 @@ import { peopleFilters } from '~/pages/people/people-filters';
|
|||||||
import { availableSorts } from '~/pages/people/people-sorts';
|
import { availableSorts } from '~/pages/people/people-sorts';
|
||||||
|
|
||||||
export function PeopleTable() {
|
export function PeopleTable() {
|
||||||
const currentViewId = useRecoilScopedValue(
|
|
||||||
currentTableViewIdState,
|
|
||||||
TableRecoilScopeContext,
|
|
||||||
);
|
|
||||||
const orderBy = useRecoilScopedValue(
|
const orderBy = useRecoilScopedValue(
|
||||||
sortsOrderByScopedState,
|
sortsOrderByScopedSelector,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
);
|
);
|
||||||
const [updateEntityMutation] = useUpdateOnePersonMutation();
|
const [updateEntityMutation] = useUpdateOnePersonMutation();
|
||||||
@ -44,7 +40,10 @@ export function PeopleTable() {
|
|||||||
objectName: objectId,
|
objectName: objectId,
|
||||||
viewFieldDefinitions: peopleViewFields,
|
viewFieldDefinitions: peopleViewFields,
|
||||||
});
|
});
|
||||||
const { handleSortsChange } = useViewSorts({ availableSorts });
|
const { persistFilters } = useViewFilters({
|
||||||
|
availableFilters: peopleFilters,
|
||||||
|
});
|
||||||
|
const { persistSorts } = useViewSorts({ availableSorts });
|
||||||
|
|
||||||
const filters = useRecoilScopedValue(
|
const filters = useRecoilScopedValue(
|
||||||
filtersScopedState,
|
filtersScopedState,
|
||||||
@ -58,6 +57,11 @@ export function PeopleTable() {
|
|||||||
const { setContextMenuEntries } = usePersonTableContextMenuEntries();
|
const { setContextMenuEntries } = usePersonTableContextMenuEntries();
|
||||||
const { setActionBarEntries } = usePersonTableActionBarEntries();
|
const { setActionBarEntries } = usePersonTableActionBarEntries();
|
||||||
|
|
||||||
|
const handleViewSubmit = useCallback(async () => {
|
||||||
|
await persistFilters();
|
||||||
|
await persistSorts();
|
||||||
|
}, [persistFilters, persistSorts]);
|
||||||
|
|
||||||
function handleImport() {
|
function handleImport() {
|
||||||
openPersonSpreadsheetImport();
|
openPersonSpreadsheetImport();
|
||||||
}
|
}
|
||||||
@ -67,15 +71,7 @@ export function PeopleTable() {
|
|||||||
<GenericEntityTableData
|
<GenericEntityTableData
|
||||||
getRequestResultKey="people"
|
getRequestResultKey="people"
|
||||||
useGetRequest={useGetPeopleQuery}
|
useGetRequest={useGetPeopleQuery}
|
||||||
orderBy={
|
orderBy={orderBy.length ? orderBy : [{ createdAt: SortOrder.Desc }]}
|
||||||
orderBy.length
|
|
||||||
? orderBy
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
createdAt: SortOrder.Desc,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
whereFilters={whereFilters}
|
whereFilters={whereFilters}
|
||||||
filterDefinitionArray={peopleFilters}
|
filterDefinitionArray={peopleFilters}
|
||||||
setContextMenuEntries={setContextMenuEntries}
|
setContextMenuEntries={setContextMenuEntries}
|
||||||
@ -85,8 +81,8 @@ export function PeopleTable() {
|
|||||||
viewName="All People"
|
viewName="All People"
|
||||||
availableSorts={availableSorts}
|
availableSorts={availableSorts}
|
||||||
onColumnsChange={handleColumnsChange}
|
onColumnsChange={handleColumnsChange}
|
||||||
onSortsUpdate={currentViewId ? handleSortsChange : undefined}
|
|
||||||
onViewsChange={handleViewsChange}
|
onViewsChange={handleViewsChange}
|
||||||
|
onViewSubmit={handleViewSubmit}
|
||||||
onImport={handleImport}
|
onImport={handleImport}
|
||||||
updateEntityMutation={({
|
updateEntityMutation={({
|
||||||
variables,
|
variables,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { ButtonPosition, ButtonProps } from './Button';
|
import { ButtonPosition, ButtonProps } from './Button';
|
||||||
@ -9,13 +9,15 @@ const StyledButtonGroupContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
type ButtonGroupProps = Pick<ButtonProps, 'variant' | 'size'> & {
|
type ButtonGroupProps = Pick<ButtonProps, 'variant' | 'size'> & {
|
||||||
children: React.ReactElement[];
|
children: ReactNode[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ButtonGroup({ children, variant, size }: ButtonGroupProps) {
|
export function ButtonGroup({ children, variant, size }: ButtonGroupProps) {
|
||||||
return (
|
return (
|
||||||
<StyledButtonGroupContainer>
|
<StyledButtonGroupContainer>
|
||||||
{React.Children.map(children, (child, index) => {
|
{React.Children.map(children, (child, index) => {
|
||||||
|
if (!React.isValidElement(child)) return null;
|
||||||
|
|
||||||
let position: ButtonPosition;
|
let position: ButtonPosition;
|
||||||
|
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export function FilterDropdownDateSearchInput({
|
|||||||
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
|
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
|
||||||
|
|
||||||
upsertFilter({
|
upsertFilter({
|
||||||
field: filterDefinitionUsedInDropdown.field,
|
key: filterDefinitionUsedInDropdown.key,
|
||||||
type: filterDefinitionUsedInDropdown.type,
|
type: filterDefinitionUsedInDropdown.type,
|
||||||
value: date.toISOString(),
|
value: date.toISOString(),
|
||||||
operand: selectedOperandInDropdown,
|
operand: selectedOperandInDropdown,
|
||||||
|
|||||||
@ -51,14 +51,14 @@ export function FilterDropdownEntitySearchSelect({
|
|||||||
selectedEntity.id === filterDropdownSelectedEntityId;
|
selectedEntity.id === filterDropdownSelectedEntityId;
|
||||||
|
|
||||||
if (clickedOnAlreadySelectedEntity) {
|
if (clickedOnAlreadySelectedEntity) {
|
||||||
removeFilter(filterDefinitionUsedInDropdown.field);
|
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||||
setFilterDropdownSelectedEntityId(null);
|
setFilterDropdownSelectedEntityId(null);
|
||||||
} else {
|
} else {
|
||||||
setFilterDropdownSelectedEntityId(selectedEntity.id);
|
setFilterDropdownSelectedEntityId(selectedEntity.id);
|
||||||
|
|
||||||
upsertFilter({
|
upsertFilter({
|
||||||
displayValue: selectedEntity.name,
|
displayValue: selectedEntity.name,
|
||||||
field: filterDefinitionUsedInDropdown.field,
|
key: filterDefinitionUsedInDropdown.key,
|
||||||
operand: selectedOperandInDropdown,
|
operand: selectedOperandInDropdown,
|
||||||
type: filterDefinitionUsedInDropdown.type,
|
type: filterDefinitionUsedInDropdown.type,
|
||||||
value: selectedEntity.id,
|
value: selectedEntity.id,
|
||||||
|
|||||||
@ -34,10 +34,10 @@ export function FilterDropdownNumberSearchInput({
|
|||||||
placeholder={filterDefinitionUsedInDropdown.label}
|
placeholder={filterDefinitionUsedInDropdown.label}
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (event.target.value === '') {
|
if (event.target.value === '') {
|
||||||
removeFilter(filterDefinitionUsedInDropdown.field);
|
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||||
} else {
|
} else {
|
||||||
upsertFilter({
|
upsertFilter({
|
||||||
field: filterDefinitionUsedInDropdown.field,
|
key: filterDefinitionUsedInDropdown.key,
|
||||||
type: filterDefinitionUsedInDropdown.type,
|
type: filterDefinitionUsedInDropdown.type,
|
||||||
value: event.target.value,
|
value: event.target.value,
|
||||||
operand: selectedOperandInDropdown,
|
operand: selectedOperandInDropdown,
|
||||||
|
|||||||
@ -48,7 +48,7 @@ export function FilterDropdownOperandSelect({
|
|||||||
|
|
||||||
if (filterDefinitionUsedInDropdown && filterCurrentlyEdited) {
|
if (filterDefinitionUsedInDropdown && filterCurrentlyEdited) {
|
||||||
upsertFilter({
|
upsertFilter({
|
||||||
field: filterCurrentlyEdited.field,
|
key: filterCurrentlyEdited.key,
|
||||||
displayValue: filterCurrentlyEdited.displayValue,
|
displayValue: filterCurrentlyEdited.displayValue,
|
||||||
operand: newOperand,
|
operand: newOperand,
|
||||||
type: filterCurrentlyEdited.type,
|
type: filterCurrentlyEdited.type,
|
||||||
|
|||||||
@ -44,10 +44,10 @@ export function FilterDropdownTextSearchInput({
|
|||||||
setFilterDropdownSearchInput(event.target.value);
|
setFilterDropdownSearchInput(event.target.value);
|
||||||
|
|
||||||
if (event.target.value === '') {
|
if (event.target.value === '') {
|
||||||
removeFilter(filterDefinitionUsedInDropdown.field);
|
removeFilter(filterDefinitionUsedInDropdown.key);
|
||||||
} else {
|
} else {
|
||||||
upsertFilter({
|
upsertFilter({
|
||||||
field: filterDefinitionUsedInDropdown.field,
|
key: filterDefinitionUsedInDropdown.key,
|
||||||
type: filterDefinitionUsedInDropdown.type,
|
type: filterDefinitionUsedInDropdown.type,
|
||||||
value: event.target.value,
|
value: event.target.value,
|
||||||
operand: selectedOperandInDropdown,
|
operand: selectedOperandInDropdown,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Context } from 'react';
|
import type { Context, ReactNode } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ type OwnProps<SortField> = {
|
|||||||
onRemoveSort: (sortId: SelectedSortType<SortField>['key']) => void;
|
onRemoveSort: (sortId: SelectedSortType<SortField>['key']) => void;
|
||||||
onCancelClick: () => void;
|
onCancelClick: () => void;
|
||||||
hasFilterButton?: boolean;
|
hasFilterButton?: boolean;
|
||||||
|
rightComponent?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledBar = styled.div`
|
const StyledBar = styled.div`
|
||||||
@ -97,6 +98,7 @@ function SortAndFilterBar<SortField>({
|
|||||||
onRemoveSort,
|
onRemoveSort,
|
||||||
onCancelClick,
|
onCancelClick,
|
||||||
hasFilterButton = false,
|
hasFilterButton = false,
|
||||||
|
rightComponent,
|
||||||
}: OwnProps<SortField>) {
|
}: OwnProps<SortField>) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -117,7 +119,7 @@ function SortAndFilterBar<SortField>({
|
|||||||
|
|
||||||
const filtersWithDefinition = filters.map((filter) => {
|
const filtersWithDefinition = filters.map((filter) => {
|
||||||
const filterDefinition = availableFilters.find((availableFilter) => {
|
const filterDefinition = availableFilters.find((availableFilter) => {
|
||||||
return availableFilter.field === filter.field;
|
return availableFilter.key === filter.key;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -170,15 +172,15 @@ function SortAndFilterBar<SortField>({
|
|||||||
{filtersWithDefinition.map((filter) => {
|
{filtersWithDefinition.map((filter) => {
|
||||||
return (
|
return (
|
||||||
<SortOrFilterChip
|
<SortOrFilterChip
|
||||||
key={filter.field}
|
key={filter.key}
|
||||||
labelKey={filter.label}
|
labelKey={filter.label}
|
||||||
labelValue={`${getOperandLabelShort(filter.operand)} ${
|
labelValue={`${getOperandLabelShort(filter.operand)} ${
|
||||||
filter.displayValue
|
filter.displayValue
|
||||||
}`}
|
}`}
|
||||||
id={filter.field}
|
id={filter.key}
|
||||||
icon={filter.icon}
|
icon={filter.icon}
|
||||||
onRemove={() => {
|
onRemove={() => {
|
||||||
removeFilter(filter.field);
|
removeFilter(filter.key);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -190,18 +192,19 @@ function SortAndFilterBar<SortField>({
|
|||||||
HotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
HotkeyScope={FiltersHotkeyScope.FilterDropdownButton}
|
||||||
color={theme.font.color.tertiary}
|
color={theme.font.color.tertiary}
|
||||||
icon={<IconPlus size={theme.icon.size.md} />}
|
icon={<IconPlus size={theme.icon.size.md} />}
|
||||||
label={`Add filter`}
|
label="Add filter"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledFilterContainer>
|
</StyledFilterContainer>
|
||||||
{filters.length + sorts.length > 0 && (
|
{filters.length + sorts.length > 0 && (
|
||||||
<StyledCancelButton
|
<StyledCancelButton
|
||||||
data-testid={'cancel-button'}
|
data-testid="cancel-button"
|
||||||
onClick={handleCancelClick}
|
onClick={handleCancelClick}
|
||||||
>
|
>
|
||||||
Cancel
|
Cancel
|
||||||
</StyledCancelButton>
|
</StyledCancelButton>
|
||||||
)}
|
)}
|
||||||
|
{rightComponent}
|
||||||
</StyledBar>
|
</StyledBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ export function useFilterCurrentlyEdited(context: Context<string | null>) {
|
|||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return filters.find(
|
return filters.find(
|
||||||
(filter) => filter.field === filterDefinitionUsedInDropdown?.field,
|
(filter) => filter.key === filterDefinitionUsedInDropdown?.key,
|
||||||
);
|
);
|
||||||
}, [filterDefinitionUsedInDropdown, filters]);
|
}, [filterDefinitionUsedInDropdown, filters]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,10 @@ import { filtersScopedState } from '../states/filtersScopedState';
|
|||||||
export function useRemoveFilter(context: Context<string | null>) {
|
export function useRemoveFilter(context: Context<string | null>) {
|
||||||
const [, setFilters] = useRecoilScopedState(filtersScopedState, context);
|
const [, setFilters] = useRecoilScopedState(filtersScopedState, context);
|
||||||
|
|
||||||
return function removeFilter(filterField: string) {
|
return function removeFilter(filterKey: string) {
|
||||||
setFilters((filters) => {
|
setFilters((filters) => {
|
||||||
return filters.filter((filter) => {
|
return filters.filter((filter) => {
|
||||||
return filter.field !== filterField;
|
return filter.key !== filterKey;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export function useUpsertFilter(context: Context<string | null>) {
|
|||||||
setFilters((filters) => {
|
setFilters((filters) => {
|
||||||
return produce(filters, (filtersDraft) => {
|
return produce(filters, (filtersDraft) => {
|
||||||
const index = filtersDraft.findIndex(
|
const index = filtersDraft.findIndex(
|
||||||
(filter) => filter.field === filterToUpsert.field,
|
(filter) => filter.key === filterToUpsert.key,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { atomFamily } from 'recoil';
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
import { Filter } from '../types/Filter';
|
import type { Filter } from '../types/Filter';
|
||||||
|
|
||||||
export const filtersScopedState = atomFamily<Filter[], string>({
|
export const filtersScopedState = atomFamily<Filter[], string>({
|
||||||
key: 'filtersScopedState',
|
key: 'filtersScopedState',
|
||||||
|
|||||||
@ -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<Record<string, Filter>>(
|
||||||
|
(result, filter) => ({ ...result, [filter.key]: filter }),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
});
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
import type { Filter } from '../types/Filter';
|
||||||
|
|
||||||
|
export const savedFiltersScopedState = atomFamily<Filter[], string | undefined>(
|
||||||
|
{
|
||||||
|
key: 'savedFiltersScopedState',
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -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<string, SelectedSortType<any>>
|
||||||
|
>((result, sort) => ({ ...result, [sort.key]: sort }), {}),
|
||||||
|
});
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
import type { SelectedSortType } from '../types/interface';
|
||||||
|
|
||||||
|
export const savedSortsScopedState = atomFamily<
|
||||||
|
SelectedSortType<any>[],
|
||||||
|
string | undefined
|
||||||
|
>({
|
||||||
|
key: 'savedSortsScopedState',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import { atomFamily, selectorFamily } from 'recoil';
|
|
||||||
|
|
||||||
import { reduceSortsToOrderBy } from '../helpers';
|
|
||||||
import { SelectedSortType } from '../types/interface';
|
|
||||||
|
|
||||||
export const sortScopedState = atomFamily<SelectedSortType<any>[], string>({
|
|
||||||
key: 'sortScopedState',
|
|
||||||
default: [],
|
|
||||||
});
|
|
||||||
|
|
||||||
export const sortsByKeyScopedState = selectorFamily({
|
|
||||||
key: 'sortsByKeyScopedState',
|
|
||||||
get:
|
|
||||||
(param: string) =>
|
|
||||||
({ get }) =>
|
|
||||||
get(sortScopedState(param)).reduce<Record<string, SelectedSortType<any>>>(
|
|
||||||
(result, sort) => ({ ...result, [sort.key]: sort }),
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const sortsOrderByScopedState = selectorFamily({
|
|
||||||
key: 'sortsOrderByScopedState',
|
|
||||||
get:
|
|
||||||
(param: string) =>
|
|
||||||
({ get }) =>
|
|
||||||
reduceSortsToOrderBy(get(sortScopedState(param))),
|
|
||||||
});
|
|
||||||
@ -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))),
|
||||||
|
});
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
import type { SelectedSortType } from '../types/interface';
|
||||||
|
|
||||||
|
export const sortsScopedState = atomFamily<SelectedSortType<any>[], string>({
|
||||||
|
key: 'sortsScopedState',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
@ -2,7 +2,7 @@ import { FilterOperand } from './FilterOperand';
|
|||||||
import { FilterType } from './FilterType';
|
import { FilterType } from './FilterType';
|
||||||
|
|
||||||
export type Filter = {
|
export type Filter = {
|
||||||
field: string;
|
key: string;
|
||||||
type: FilterType;
|
type: FilterType;
|
||||||
value: string;
|
value: string;
|
||||||
displayValue: string;
|
displayValue: string;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { FilterType } from './FilterType';
|
import { FilterType } from './FilterType';
|
||||||
|
|
||||||
export type FilterDefinition = {
|
export type FilterDefinition = {
|
||||||
field: string;
|
key: string;
|
||||||
label: string;
|
label: string;
|
||||||
icon: JSX.Element;
|
icon: JSX.Element;
|
||||||
type: FilterType;
|
type: FilterType;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { FilterDefinition } from './FilterDefinition';
|
import { FilterDefinition } from './FilterDefinition';
|
||||||
|
|
||||||
export type FilterDefinitionByEntity<T> = FilterDefinition & {
|
export type FilterDefinitionByEntity<T> = FilterDefinition & {
|
||||||
field: keyof T;
|
key: keyof T;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1 @@
|
|||||||
export type FilterOperand =
|
export { ViewFilterOperand as FilterOperand } from '~/generated/graphql';
|
||||||
| 'contains'
|
|
||||||
| 'does-not-contain'
|
|
||||||
| 'greater-than'
|
|
||||||
| 'less-than'
|
|
||||||
| 'is'
|
|
||||||
| 'is-not';
|
|
||||||
|
|||||||
@ -2,17 +2,17 @@ import { FilterOperand } from '../types/FilterOperand';
|
|||||||
|
|
||||||
export function getOperandLabel(operand: FilterOperand | null | undefined) {
|
export function getOperandLabel(operand: FilterOperand | null | undefined) {
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
case 'contains':
|
case FilterOperand.Contains:
|
||||||
return 'Contains';
|
return 'Contains';
|
||||||
case 'does-not-contain':
|
case FilterOperand.DoesNotContain:
|
||||||
return "Doesn't contain";
|
return "Doesn't contain";
|
||||||
case 'greater-than':
|
case FilterOperand.GreaterThan:
|
||||||
return 'Greater than';
|
return 'Greater than';
|
||||||
case 'less-than':
|
case FilterOperand.LessThan:
|
||||||
return 'Less than';
|
return 'Less than';
|
||||||
case 'is':
|
case FilterOperand.Is:
|
||||||
return 'Is';
|
return 'Is';
|
||||||
case 'is-not':
|
case FilterOperand.IsNot:
|
||||||
return 'Is not';
|
return 'Is not';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
@ -22,15 +22,15 @@ export function getOperandLabelShort(
|
|||||||
operand: FilterOperand | null | undefined,
|
operand: FilterOperand | null | undefined,
|
||||||
) {
|
) {
|
||||||
switch (operand) {
|
switch (operand) {
|
||||||
case 'is':
|
case FilterOperand.Is:
|
||||||
case 'contains':
|
case FilterOperand.Contains:
|
||||||
return ': ';
|
return ': ';
|
||||||
case 'is-not':
|
case FilterOperand.IsNot:
|
||||||
case 'does-not-contain':
|
case FilterOperand.DoesNotContain:
|
||||||
return ': Not';
|
return ': Not';
|
||||||
case 'greater-than':
|
case FilterOperand.GreaterThan:
|
||||||
return '\u00A0> ';
|
return '\u00A0> ';
|
||||||
case 'less-than':
|
case FilterOperand.LessThan:
|
||||||
return '\u00A0< ';
|
return '\u00A0< ';
|
||||||
default:
|
default:
|
||||||
return ': ';
|
return ': ';
|
||||||
|
|||||||
@ -6,12 +6,12 @@ export function getOperandsForFilterType(
|
|||||||
): FilterOperand[] {
|
): FilterOperand[] {
|
||||||
switch (filterType) {
|
switch (filterType) {
|
||||||
case 'text':
|
case 'text':
|
||||||
return ['contains', 'does-not-contain'];
|
return [FilterOperand.Contains, FilterOperand.DoesNotContain];
|
||||||
case 'number':
|
case 'number':
|
||||||
case 'date':
|
case 'date':
|
||||||
return ['greater-than', 'less-than'];
|
return [FilterOperand.GreaterThan, FilterOperand.LessThan];
|
||||||
case 'entity':
|
case 'entity':
|
||||||
return ['is', 'is-not'];
|
return [FilterOperand.Is, FilterOperand.IsNot];
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
import { QueryMode } from '~/generated/graphql';
|
import { QueryMode } from '~/generated/graphql';
|
||||||
|
|
||||||
import { Filter } from '../types/Filter';
|
import { Filter } from '../types/Filter';
|
||||||
|
import { FilterOperand } from '../types/FilterOperand';
|
||||||
|
|
||||||
export function turnFilterIntoWhereClause(filter: Filter) {
|
export function turnFilterIntoWhereClause(filter: Filter) {
|
||||||
switch (filter.type) {
|
switch (filter.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case 'contains':
|
case FilterOperand.Contains:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
contains: filter.value,
|
contains: filter.value,
|
||||||
mode: QueryMode.Insensitive,
|
mode: QueryMode.Insensitive,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case 'does-not-contain':
|
case FilterOperand.DoesNotContain:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
not: {
|
not: {
|
||||||
contains: filter.value,
|
contains: filter.value,
|
||||||
mode: QueryMode.Insensitive,
|
mode: QueryMode.Insensitive,
|
||||||
@ -29,15 +30,15 @@ export function turnFilterIntoWhereClause(filter: Filter) {
|
|||||||
}
|
}
|
||||||
case 'number':
|
case 'number':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case 'greater-than':
|
case FilterOperand.GreaterThan:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
gte: parseFloat(filter.value),
|
gte: parseFloat(filter.value),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case 'less-than':
|
case FilterOperand.LessThan:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
lte: parseFloat(filter.value),
|
lte: parseFloat(filter.value),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -48,15 +49,15 @@ export function turnFilterIntoWhereClause(filter: Filter) {
|
|||||||
}
|
}
|
||||||
case 'date':
|
case 'date':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case 'greater-than':
|
case FilterOperand.GreaterThan:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
gte: filter.value,
|
gte: filter.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case 'less-than':
|
case FilterOperand.LessThan:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
lte: filter.value,
|
lte: filter.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -67,15 +68,15 @@ export function turnFilterIntoWhereClause(filter: Filter) {
|
|||||||
}
|
}
|
||||||
case 'entity':
|
case 'entity':
|
||||||
switch (filter.operand) {
|
switch (filter.operand) {
|
||||||
case 'is':
|
case FilterOperand.Is:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
equals: filter.value,
|
equals: filter.value,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
case 'is-not':
|
case FilterOperand.IsNot:
|
||||||
return {
|
return {
|
||||||
[filter.field]: {
|
[filter.key]: {
|
||||||
not: { equals: filter.value },
|
not: { equals: filter.value },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type {
|
|||||||
ViewFieldDefinition,
|
ViewFieldDefinition,
|
||||||
ViewFieldMetadata,
|
ViewFieldMetadata,
|
||||||
} from '@/ui/editable-field/types/ViewField';
|
} 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 { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||||
|
|
||||||
@ -97,8 +97,8 @@ type OwnProps<SortField> = {
|
|||||||
viewIcon?: React.ReactNode;
|
viewIcon?: React.ReactNode;
|
||||||
availableSorts?: Array<SortType<SortField>>;
|
availableSorts?: Array<SortType<SortField>>;
|
||||||
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
|
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
|
||||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
|
||||||
onViewsChange?: (views: TableView[]) => void;
|
onViewsChange?: (views: TableView[]) => void;
|
||||||
|
onViewSubmit?: () => void;
|
||||||
onImport?: () => void;
|
onImport?: () => void;
|
||||||
updateEntityMutation: any;
|
updateEntityMutation: any;
|
||||||
};
|
};
|
||||||
@ -107,8 +107,8 @@ export function EntityTable<SortField>({
|
|||||||
viewName,
|
viewName,
|
||||||
availableSorts,
|
availableSorts,
|
||||||
onColumnsChange,
|
onColumnsChange,
|
||||||
onSortsUpdate,
|
|
||||||
onViewsChange,
|
onViewsChange,
|
||||||
|
onViewSubmit,
|
||||||
onImport,
|
onImport,
|
||||||
updateEntityMutation,
|
updateEntityMutation,
|
||||||
}: OwnProps<SortField>) {
|
}: OwnProps<SortField>) {
|
||||||
@ -136,8 +136,8 @@ export function EntityTable<SortField>({
|
|||||||
viewName={viewName}
|
viewName={viewName}
|
||||||
availableSorts={availableSorts}
|
availableSorts={availableSorts}
|
||||||
onColumnsChange={onColumnsChange}
|
onColumnsChange={onColumnsChange}
|
||||||
onSortsUpdate={onSortsUpdate}
|
|
||||||
onViewsChange={onViewsChange}
|
onViewsChange={onViewsChange}
|
||||||
|
onViewSubmit={onViewSubmit}
|
||||||
onImport={onImport}
|
onImport={onImport}
|
||||||
/>
|
/>
|
||||||
<StyledTableWrapper>
|
<StyledTableWrapper>
|
||||||
|
|||||||
@ -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 (
|
||||||
|
<StyledContainer>
|
||||||
|
<ButtonGroup size={ButtonSize.Small}>
|
||||||
|
<Button
|
||||||
|
title="Update view"
|
||||||
|
disabled={!currentViewId}
|
||||||
|
onClick={handleViewSubmit}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size={ButtonSize.Small}
|
||||||
|
icon={<IconChevronDown />}
|
||||||
|
onClick={handleArrowDownButtonClick}
|
||||||
|
/>
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
|
{isDropdownOpen && (
|
||||||
|
<StyledDropdownMenuContainer onClose={handleDropdownClose}>
|
||||||
|
<DropdownMenuItemsContainer>
|
||||||
|
<DropdownMenuItem onClick={handleCreateViewButtonClick}>
|
||||||
|
<IconPlus size={theme.icon.size.md} />
|
||||||
|
Create view
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuItemsContainer>
|
||||||
|
</StyledDropdownMenuContainer>
|
||||||
|
)}
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,13 +1,17 @@
|
|||||||
import { type MouseEvent, useCallback, useEffect, useState } from 'react';
|
import { type MouseEvent, useCallback, useEffect, useState } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { IconButton } from '@/ui/button/components/IconButton';
|
import { IconButton } from '@/ui/button/components/IconButton';
|
||||||
import { DropdownMenuItem } from '@/ui/dropdown/components/DropdownMenuItem';
|
import { DropdownMenuItem } from '@/ui/dropdown/components/DropdownMenuItem';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { DropdownMenuSeparator } from '@/ui/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/dropdown/components/DropdownMenuSeparator';
|
||||||
import DropdownButton from '@/ui/filter-n-sort/components/DropdownButton';
|
import DropdownButton from '@/ui/filter-n-sort/components/DropdownButton';
|
||||||
|
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 {
|
import {
|
||||||
IconChevronDown,
|
IconChevronDown,
|
||||||
IconList,
|
IconList,
|
||||||
@ -23,6 +27,7 @@ import {
|
|||||||
tableViewsState,
|
tableViewsState,
|
||||||
} from '@/ui/table/states/tableViewsState';
|
} from '@/ui/table/states/tableViewsState';
|
||||||
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
|
||||||
|
import { useContextScopeId } from '@/ui/utilities/recoil-scope/hooks/useContextScopeId';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
|
||||||
@ -59,6 +64,8 @@ export const TableViewsDropdownButton = ({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [isUnfolded, setIsUnfolded] = useState(false);
|
const [isUnfolded, setIsUnfolded] = useState(false);
|
||||||
|
|
||||||
|
const tableScopeId = useContextScopeId(TableRecoilScopeContext);
|
||||||
|
|
||||||
const currentView = useRecoilScopedValue(
|
const currentView = useRecoilScopedValue(
|
||||||
currentTableViewState,
|
currentTableViewState,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
@ -78,11 +85,21 @@ export const TableViewsDropdownButton = ({
|
|||||||
setHotkeyScopeAndMemorizePreviousScope,
|
setHotkeyScopeAndMemorizePreviousScope,
|
||||||
} = usePreviousHotkeyScope();
|
} = usePreviousHotkeyScope();
|
||||||
|
|
||||||
const handleViewSelect = useCallback(
|
const handleViewSelect = useRecoilCallback(
|
||||||
(viewId?: string) => {
|
({ set, snapshot }) =>
|
||||||
setCurrentViewId(viewId);
|
async (viewId?: string) => {
|
||||||
setIsUnfolded(false);
|
const savedFilters = await snapshot.getPromise(
|
||||||
},
|
savedFiltersScopedState(viewId),
|
||||||
|
);
|
||||||
|
const savedSorts = await snapshot.getPromise(
|
||||||
|
savedSortsScopedState(viewId),
|
||||||
|
);
|
||||||
|
|
||||||
|
set(filtersScopedState(tableScopeId), savedFilters);
|
||||||
|
set(sortsScopedState(tableScopeId), savedSorts);
|
||||||
|
setCurrentViewId(viewId);
|
||||||
|
setIsUnfolded(false);
|
||||||
|
},
|
||||||
[setCurrentViewId],
|
[setCurrentViewId],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -7,13 +7,14 @@ import type {
|
|||||||
import { FilterDropdownButton } from '@/ui/filter-n-sort/components/FilterDropdownButton';
|
import { FilterDropdownButton } from '@/ui/filter-n-sort/components/FilterDropdownButton';
|
||||||
import SortAndFilterBar from '@/ui/filter-n-sort/components/SortAndFilterBar';
|
import SortAndFilterBar from '@/ui/filter-n-sort/components/SortAndFilterBar';
|
||||||
import { SortDropdownButton } from '@/ui/filter-n-sort/components/SortDropdownButton';
|
import { SortDropdownButton } from '@/ui/filter-n-sort/components/SortDropdownButton';
|
||||||
import { sortScopedState } from '@/ui/filter-n-sort/states/sortScopedState';
|
import { sortsScopedState } from '@/ui/filter-n-sort/states/sortsScopedState';
|
||||||
import { FiltersHotkeyScope } from '@/ui/filter-n-sort/types/FiltersHotkeyScope';
|
import { FiltersHotkeyScope } from '@/ui/filter-n-sort/types/FiltersHotkeyScope';
|
||||||
import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface';
|
import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface';
|
||||||
import { TableOptionsDropdownButton } from '@/ui/table/options/components/TableOptionsDropdownButton';
|
import { TableOptionsDropdownButton } from '@/ui/table/options/components/TableOptionsDropdownButton';
|
||||||
import { TopBar } from '@/ui/top-bar/TopBar';
|
import { TopBar } from '@/ui/top-bar/TopBar';
|
||||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
|
import { TableUpdateViewButtonGroup } from '../../options/components/TableUpdateViewButtonGroup';
|
||||||
import { TableViewsDropdownButton } from '../../options/components/TableViewsDropdownButton';
|
import { TableViewsDropdownButton } from '../../options/components/TableViewsDropdownButton';
|
||||||
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
import { TableRecoilScopeContext } from '../../states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
import type { TableView } from '../../states/tableViewsState';
|
import type { TableView } from '../../states/tableViewsState';
|
||||||
@ -24,8 +25,8 @@ type OwnProps<SortField> = {
|
|||||||
viewName: string;
|
viewName: string;
|
||||||
availableSorts?: Array<SortType<SortField>>;
|
availableSorts?: Array<SortType<SortField>>;
|
||||||
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
|
onColumnsChange?: (columns: ViewFieldDefinition<ViewFieldMetadata>[]) => void;
|
||||||
onSortsUpdate?: (sorts: Array<SelectedSortType<SortField>>) => void;
|
|
||||||
onViewsChange?: (views: TableView[]) => void;
|
onViewsChange?: (views: TableView[]) => void;
|
||||||
|
onViewSubmit?: () => void;
|
||||||
onImport?: () => void;
|
onImport?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -33,30 +34,29 @@ export function TableHeader<SortField>({
|
|||||||
viewName,
|
viewName,
|
||||||
availableSorts,
|
availableSorts,
|
||||||
onColumnsChange,
|
onColumnsChange,
|
||||||
onSortsUpdate,
|
|
||||||
onViewsChange,
|
onViewsChange,
|
||||||
|
onViewSubmit,
|
||||||
onImport,
|
onImport,
|
||||||
}: OwnProps<SortField>) {
|
}: OwnProps<SortField>) {
|
||||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
||||||
sortScopedState,
|
sortsScopedState,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
);
|
);
|
||||||
const handleSortsUpdate = onSortsUpdate ?? setSorts;
|
|
||||||
|
|
||||||
const sortSelect = useCallback(
|
const sortSelect = useCallback(
|
||||||
(newSort: SelectedSortType<SortField>) => {
|
(newSort: SelectedSortType<SortField>) => {
|
||||||
const newSorts = updateSortOrFilterByKey(sorts, newSort);
|
const newSorts = updateSortOrFilterByKey(sorts, newSort);
|
||||||
handleSortsUpdate(newSorts);
|
setSorts(newSorts);
|
||||||
},
|
},
|
||||||
[handleSortsUpdate, sorts],
|
[setSorts, sorts],
|
||||||
);
|
);
|
||||||
|
|
||||||
const sortUnselect = useCallback(
|
const sortUnselect = useCallback(
|
||||||
(sortKey: string) => {
|
(sortKey: string) => {
|
||||||
const newSorts = sorts.filter((sort) => sort.key !== sortKey);
|
const newSorts = sorts.filter((sort) => sort.key !== sortKey);
|
||||||
handleSortsUpdate(newSorts);
|
setSorts(newSorts);
|
||||||
},
|
},
|
||||||
[handleSortsUpdate, sorts],
|
[setSorts, sorts],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -65,7 +65,7 @@ export function TableHeader<SortField>({
|
|||||||
<TableViewsDropdownButton
|
<TableViewsDropdownButton
|
||||||
defaultViewName={viewName}
|
defaultViewName={viewName}
|
||||||
onViewsChange={onViewsChange}
|
onViewsChange={onViewsChange}
|
||||||
HotkeyScope={TableViewsHotkeyScope.Dropdown}
|
HotkeyScope={TableViewsHotkeyScope.ListDropdown}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
displayBottomBorder={false}
|
displayBottomBorder={false}
|
||||||
@ -97,10 +97,14 @@ export function TableHeader<SortField>({
|
|||||||
context={TableRecoilScopeContext}
|
context={TableRecoilScopeContext}
|
||||||
sorts={sorts}
|
sorts={sorts}
|
||||||
onRemoveSort={sortUnselect}
|
onRemoveSort={sortUnselect}
|
||||||
onCancelClick={() => {
|
onCancelClick={() => setSorts([])}
|
||||||
handleSortsUpdate([]);
|
|
||||||
}}
|
|
||||||
hasFilterButton
|
hasFilterButton
|
||||||
|
rightComponent={
|
||||||
|
<TableUpdateViewButtonGroup
|
||||||
|
onViewSubmit={onViewSubmit}
|
||||||
|
HotkeyScope={TableViewsHotkeyScope.CreateDropdown}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export enum TableViewsHotkeyScope {
|
export enum TableViewsHotkeyScope {
|
||||||
Dropdown = 'table-views-dropdown',
|
ListDropdown = 'table-views-list-dropdown',
|
||||||
|
CreateDropdown = 'table-views-create-dropdown',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const CREATE_VIEW_FILTERS = gql`
|
||||||
|
mutation CreateViewFilters($data: [ViewFilterCreateManyInput!]!) {
|
||||||
|
createManyViewFilter(data: $data) {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const DELETE_VIEW_FILTERS = gql`
|
||||||
|
mutation DeleteViewFilters($where: ViewFilterWhereInput!) {
|
||||||
|
deleteManyViewFilter(where: $where) {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const UPDATE_VIEW_FILTER = gql`
|
||||||
|
mutation UpdateViewFilter(
|
||||||
|
$data: ViewFilterUpdateInput!
|
||||||
|
$where: ViewFilterWhereUniqueInput!
|
||||||
|
) {
|
||||||
|
viewFilter: updateOneViewFilter(data: $data, where: $where) {
|
||||||
|
displayValue
|
||||||
|
key
|
||||||
|
name
|
||||||
|
operand
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
13
front/src/modules/views/graphql/queries/getViewFilters.ts
Normal file
13
front/src/modules/views/graphql/queries/getViewFilters.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
export const GET_VIEW_FILTERS = gql`
|
||||||
|
query GetViewFilters($where: ViewFilterWhereInput) {
|
||||||
|
viewFilters: findManyViewFilter(where: $where) {
|
||||||
|
displayValue
|
||||||
|
key
|
||||||
|
name
|
||||||
|
operand
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
172
front/src/modules/views/hooks/useViewFilters.ts
Normal file
172
front/src/modules/views/hooks/useViewFilters.ts
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||||
|
import { savedFiltersByKeyScopedSelector } from '@/ui/filter-n-sort/states/savedFiltersByKeyScopedSelector';
|
||||||
|
import { savedFiltersScopedState } from '@/ui/filter-n-sort/states/savedFiltersScopedState';
|
||||||
|
import type { Filter } from '@/ui/filter-n-sort/types/Filter';
|
||||||
|
import type { FilterDefinitionByEntity } from '@/ui/filter-n-sort/types/FilterDefinitionByEntity';
|
||||||
|
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
|
||||||
|
import { currentTableViewIdState } from '@/ui/table/states/tableViewsState';
|
||||||
|
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||||
|
import {
|
||||||
|
useCreateViewFiltersMutation,
|
||||||
|
useDeleteViewFiltersMutation,
|
||||||
|
useGetViewFiltersQuery,
|
||||||
|
useUpdateViewFilterMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
|
|
||||||
|
export const useViewFilters = <Entity>({
|
||||||
|
availableFilters,
|
||||||
|
}: {
|
||||||
|
availableFilters: FilterDefinitionByEntity<Entity>[];
|
||||||
|
}) => {
|
||||||
|
const currentViewId = useRecoilScopedValue(
|
||||||
|
currentTableViewIdState,
|
||||||
|
TableRecoilScopeContext,
|
||||||
|
);
|
||||||
|
const [filters, setFilters] = useRecoilScopedState(
|
||||||
|
filtersScopedState,
|
||||||
|
TableRecoilScopeContext,
|
||||||
|
);
|
||||||
|
const [, setSavedFilters] = useRecoilState(
|
||||||
|
savedFiltersScopedState(currentViewId),
|
||||||
|
);
|
||||||
|
const savedFiltersByKey = useRecoilValue(
|
||||||
|
savedFiltersByKeyScopedSelector(currentViewId),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { refetch } = useGetViewFiltersQuery({
|
||||||
|
skip: !currentViewId,
|
||||||
|
variables: {
|
||||||
|
where: {
|
||||||
|
viewId: { equals: currentViewId },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onCompleted: (data) => {
|
||||||
|
const nextFilters = data.viewFilters
|
||||||
|
.map(({ __typename, name: _name, ...viewFilter }) => {
|
||||||
|
const availableFilter = availableFilters.find(
|
||||||
|
(filter) => filter.key === viewFilter.key,
|
||||||
|
);
|
||||||
|
|
||||||
|
return availableFilter
|
||||||
|
? {
|
||||||
|
...viewFilter,
|
||||||
|
displayValue: viewFilter.displayValue ?? viewFilter.value,
|
||||||
|
type: availableFilter.type,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
})
|
||||||
|
.filter((filter): filter is Filter => !!filter);
|
||||||
|
|
||||||
|
if (!isDeeplyEqual(filters, nextFilters)) {
|
||||||
|
setSavedFilters(nextFilters);
|
||||||
|
setFilters(nextFilters);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [createViewFiltersMutation] = useCreateViewFiltersMutation();
|
||||||
|
const [updateViewFilterMutation] = useUpdateViewFilterMutation();
|
||||||
|
const [deleteViewFiltersMutation] = useDeleteViewFiltersMutation();
|
||||||
|
|
||||||
|
const createViewFilters = useCallback(
|
||||||
|
(filters: Filter[]) => {
|
||||||
|
if (!currentViewId || !filters.length) return;
|
||||||
|
|
||||||
|
return createViewFiltersMutation({
|
||||||
|
variables: {
|
||||||
|
data: filters.map((filter) => ({
|
||||||
|
displayValue: filter.displayValue ?? filter.value,
|
||||||
|
key: filter.key,
|
||||||
|
name:
|
||||||
|
availableFilters.find(({ key }) => key === filter.key)?.label ??
|
||||||
|
'',
|
||||||
|
operand: filter.operand,
|
||||||
|
value: filter.value,
|
||||||
|
viewId: currentViewId,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[availableFilters, createViewFiltersMutation, currentViewId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const updateViewFilters = useCallback(
|
||||||
|
(filters: Filter[]) => {
|
||||||
|
if (!currentViewId || !filters.length) return;
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
filters.map((filter) =>
|
||||||
|
updateViewFilterMutation({
|
||||||
|
variables: {
|
||||||
|
data: {
|
||||||
|
displayValue: filter.displayValue ?? filter.value,
|
||||||
|
operand: filter.operand,
|
||||||
|
value: filter.value,
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
viewId_key: { key: filter.key, viewId: currentViewId },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[currentViewId, updateViewFilterMutation],
|
||||||
|
);
|
||||||
|
|
||||||
|
const deleteViewFilters = useCallback(
|
||||||
|
(filterKeys: string[]) => {
|
||||||
|
if (!currentViewId || !filterKeys.length) return;
|
||||||
|
|
||||||
|
return deleteViewFiltersMutation({
|
||||||
|
variables: {
|
||||||
|
where: {
|
||||||
|
key: { in: filterKeys },
|
||||||
|
viewId: { equals: currentViewId },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[currentViewId, deleteViewFiltersMutation],
|
||||||
|
);
|
||||||
|
|
||||||
|
const persistFilters = useCallback(async () => {
|
||||||
|
if (!currentViewId) return;
|
||||||
|
|
||||||
|
const filtersToCreate = filters.filter(
|
||||||
|
(filter) => !savedFiltersByKey[filter.key],
|
||||||
|
);
|
||||||
|
await createViewFilters(filtersToCreate);
|
||||||
|
|
||||||
|
const filtersToUpdate = filters.filter(
|
||||||
|
(filter) =>
|
||||||
|
savedFiltersByKey[filter.key] &&
|
||||||
|
(savedFiltersByKey[filter.key].operand !== filter.operand ||
|
||||||
|
savedFiltersByKey[filter.key].value !== filter.value),
|
||||||
|
);
|
||||||
|
await updateViewFilters(filtersToUpdate);
|
||||||
|
|
||||||
|
const filterKeys = filters.map((filter) => filter.key);
|
||||||
|
const filterKeysToDelete = Object.keys(savedFiltersByKey).filter(
|
||||||
|
(previousFilterKey) => !filterKeys.includes(previousFilterKey),
|
||||||
|
);
|
||||||
|
await deleteViewFilters(filterKeysToDelete);
|
||||||
|
|
||||||
|
return refetch();
|
||||||
|
}, [
|
||||||
|
currentViewId,
|
||||||
|
filters,
|
||||||
|
createViewFilters,
|
||||||
|
updateViewFilters,
|
||||||
|
savedFiltersByKey,
|
||||||
|
deleteViewFilters,
|
||||||
|
refetch,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { persistFilters };
|
||||||
|
};
|
||||||
@ -1,10 +1,9 @@
|
|||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import {
|
import { savedSortsByKeyScopedSelector } from '@/ui/filter-n-sort/states/savedSortsByKeyScopedSelector';
|
||||||
sortsByKeyScopedState,
|
import { savedSortsScopedState } from '@/ui/filter-n-sort/states/savedSortsScopedState';
|
||||||
sortScopedState,
|
import { sortsScopedState } from '@/ui/filter-n-sort/states/sortsScopedState';
|
||||||
} from '@/ui/filter-n-sort/states/sortScopedState';
|
|
||||||
import type {
|
import type {
|
||||||
SelectedSortType,
|
SelectedSortType,
|
||||||
SortType,
|
SortType,
|
||||||
@ -20,8 +19,7 @@ import {
|
|||||||
useUpdateViewSortMutation,
|
useUpdateViewSortMutation,
|
||||||
ViewSortDirection,
|
ViewSortDirection,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||||
import { GET_VIEW_SORTS } from '../graphql/queries/getViewSorts';
|
|
||||||
|
|
||||||
export const useViewSorts = <SortField>({
|
export const useViewSorts = <SortField>({
|
||||||
availableSorts,
|
availableSorts,
|
||||||
@ -32,20 +30,18 @@ export const useViewSorts = <SortField>({
|
|||||||
currentTableViewIdState,
|
currentTableViewIdState,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
);
|
);
|
||||||
const [, setSorts] = useRecoilScopedState(
|
const [sorts, setSorts] = useRecoilScopedState(
|
||||||
sortScopedState,
|
sortsScopedState,
|
||||||
TableRecoilScopeContext,
|
TableRecoilScopeContext,
|
||||||
);
|
);
|
||||||
const sortsByKey = useRecoilScopedValue(
|
const [, setSavedSorts] = useRecoilState(
|
||||||
sortsByKeyScopedState,
|
savedSortsScopedState(currentViewId),
|
||||||
TableRecoilScopeContext,
|
);
|
||||||
|
const savedSortsByKey = useRecoilValue(
|
||||||
|
savedSortsByKeyScopedSelector(currentViewId),
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const { refetch } = useGetViewSortsQuery({
|
||||||
if (!currentViewId) setSorts([]);
|
|
||||||
}, [currentViewId, setSorts]);
|
|
||||||
|
|
||||||
useGetViewSortsQuery({
|
|
||||||
skip: !currentViewId,
|
skip: !currentViewId,
|
||||||
variables: {
|
variables: {
|
||||||
where: {
|
where: {
|
||||||
@ -53,23 +49,26 @@ export const useViewSorts = <SortField>({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
setSorts(
|
const nextSorts = data.viewSorts
|
||||||
data.viewSorts
|
.map((viewSort) => {
|
||||||
.map((viewSort) => {
|
const availableSort = availableSorts.find(
|
||||||
const availableSort = availableSorts.find(
|
(sort) => sort.key === viewSort.key,
|
||||||
(sort) => sort.key === viewSort.key,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return availableSort
|
return availableSort
|
||||||
? {
|
? {
|
||||||
...availableSort,
|
...availableSort,
|
||||||
label: viewSort.name,
|
label: viewSort.name,
|
||||||
order: viewSort.direction.toLowerCase(),
|
order: viewSort.direction.toLowerCase(),
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
})
|
})
|
||||||
.filter((sort): sort is SelectedSortType<SortField> => !!sort),
|
.filter((sort): sort is SelectedSortType<SortField> => !!sort);
|
||||||
);
|
|
||||||
|
if (!isDeeplyEqual(sorts, nextSorts)) {
|
||||||
|
setSavedSorts(nextSorts);
|
||||||
|
setSorts(nextSorts);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -90,7 +89,6 @@ export const useViewSorts = <SortField>({
|
|||||||
viewId: currentViewId,
|
viewId: currentViewId,
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[createViewSortsMutation, currentViewId],
|
[createViewSortsMutation, currentViewId],
|
||||||
@ -111,7 +109,6 @@ export const useViewSorts = <SortField>({
|
|||||||
viewId_key: { key: sort.key, viewId: currentViewId },
|
viewId_key: { key: sort.key, viewId: currentViewId },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -130,45 +127,40 @@ export const useViewSorts = <SortField>({
|
|||||||
viewId: { equals: currentViewId },
|
viewId: { equals: currentViewId },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[currentViewId, deleteViewSortsMutation],
|
[currentViewId, deleteViewSortsMutation],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSortsChange = useCallback(
|
const persistSorts = useCallback(async () => {
|
||||||
async (nextSorts: SelectedSortType<SortField>[]) => {
|
if (!currentViewId) return;
|
||||||
if (!currentViewId) return;
|
|
||||||
|
|
||||||
setSorts(nextSorts);
|
const sortsToCreate = sorts.filter((sort) => !savedSortsByKey[sort.key]);
|
||||||
|
await createViewSorts(sortsToCreate);
|
||||||
|
|
||||||
const sortsToCreate = nextSorts.filter(
|
const sortsToUpdate = sorts.filter(
|
||||||
(nextSort) => !sortsByKey[nextSort.key],
|
(sort) =>
|
||||||
);
|
savedSortsByKey[sort.key] &&
|
||||||
await createViewSorts(sortsToCreate);
|
savedSortsByKey[sort.key].order !== sort.order,
|
||||||
|
);
|
||||||
|
await updateViewSorts(sortsToUpdate);
|
||||||
|
|
||||||
const sortsToUpdate = nextSorts.filter(
|
const sortKeys = sorts.map((sort) => sort.key);
|
||||||
(nextSort) =>
|
const sortKeysToDelete = Object.keys(savedSortsByKey).filter(
|
||||||
sortsByKey[nextSort.key] &&
|
(previousSortKey) => !sortKeys.includes(previousSortKey),
|
||||||
sortsByKey[nextSort.key].order !== nextSort.order,
|
);
|
||||||
);
|
await deleteViewSorts(sortKeysToDelete);
|
||||||
await updateViewSorts(sortsToUpdate);
|
|
||||||
|
|
||||||
const nextSortKeys = nextSorts.map((nextSort) => nextSort.key);
|
return refetch();
|
||||||
const sortKeysToDelete = Object.keys(sortsByKey).filter(
|
}, [
|
||||||
(previousSortKey) => !nextSortKeys.includes(previousSortKey),
|
currentViewId,
|
||||||
);
|
sorts,
|
||||||
return deleteViewSorts(sortKeysToDelete);
|
createViewSorts,
|
||||||
},
|
updateViewSorts,
|
||||||
[
|
savedSortsByKey,
|
||||||
createViewSorts,
|
deleteViewSorts,
|
||||||
currentViewId,
|
refetch,
|
||||||
deleteViewSorts,
|
]);
|
||||||
setSorts,
|
|
||||||
sortsByKey,
|
|
||||||
updateViewSorts,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
return { handleSortsChange };
|
return { persistSorts };
|
||||||
};
|
};
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import { Company } from '~/generated/graphql';
|
|||||||
|
|
||||||
export const companiesFilters: FilterDefinitionByEntity<Company>[] = [
|
export const companiesFilters: FilterDefinitionByEntity<Company>[] = [
|
||||||
{
|
{
|
||||||
field: 'name',
|
key: 'name',
|
||||||
label: 'Name',
|
label: 'Name',
|
||||||
icon: (
|
icon: (
|
||||||
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
||||||
@ -22,31 +22,31 @@ export const companiesFilters: FilterDefinitionByEntity<Company>[] = [
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'employees',
|
key: 'employees',
|
||||||
label: 'Employees',
|
label: 'Employees',
|
||||||
icon: <IconUsers size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconUsers size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'domainName',
|
key: 'domainName',
|
||||||
label: 'URL',
|
label: 'URL',
|
||||||
icon: <IconLink size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconLink size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'address',
|
key: 'address',
|
||||||
label: 'Address',
|
label: 'Address',
|
||||||
icon: <IconMap size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconMap size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'createdAt',
|
key: 'createdAt',
|
||||||
label: 'Created at',
|
label: 'Created at',
|
||||||
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'date',
|
type: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'accountOwnerId',
|
key: 'accountOwnerId',
|
||||||
label: 'Account owner',
|
label: 'Account owner',
|
||||||
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'entity',
|
type: 'entity',
|
||||||
|
|||||||
@ -15,19 +15,19 @@ import { FilterDropdownPeopleSearchSelect } from '../../modules/people/component
|
|||||||
export const opportunitiesFilters: FilterDefinitionByEntity<PipelineProgress>[] =
|
export const opportunitiesFilters: FilterDefinitionByEntity<PipelineProgress>[] =
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
field: 'amount',
|
key: 'amount',
|
||||||
label: 'Amount',
|
label: 'Amount',
|
||||||
icon: <IconCurrencyDollar size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconCurrencyDollar size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'closeDate',
|
key: 'closeDate',
|
||||||
label: 'Close date',
|
label: 'Close date',
|
||||||
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'date',
|
type: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'companyId',
|
key: 'companyId',
|
||||||
label: 'Company',
|
label: 'Company',
|
||||||
icon: (
|
icon: (
|
||||||
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
||||||
@ -40,7 +40,7 @@ export const opportunitiesFilters: FilterDefinitionByEntity<PipelineProgress>[]
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'pointOfContactId',
|
key: 'pointOfContactId',
|
||||||
label: 'Point of contact',
|
label: 'Point of contact',
|
||||||
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'entity',
|
type: 'entity',
|
||||||
|
|||||||
@ -14,25 +14,25 @@ import { Person } from '~/generated/graphql';
|
|||||||
|
|
||||||
export const peopleFilters: FilterDefinitionByEntity<Person>[] = [
|
export const peopleFilters: FilterDefinitionByEntity<Person>[] = [
|
||||||
{
|
{
|
||||||
field: 'firstName',
|
key: 'firstName',
|
||||||
label: 'First name',
|
label: 'First name',
|
||||||
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'lastName',
|
key: 'lastName',
|
||||||
label: 'Last name',
|
label: 'Last name',
|
||||||
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconUser size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'email',
|
key: 'email',
|
||||||
label: 'Email',
|
label: 'Email',
|
||||||
icon: <IconMail size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconMail size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'companyId',
|
key: 'companyId',
|
||||||
label: 'Company',
|
label: 'Company',
|
||||||
icon: (
|
icon: (
|
||||||
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
<IconBuildingSkyscraper size={icon.size.md} stroke={icon.stroke.sm} />
|
||||||
@ -43,19 +43,19 @@ export const peopleFilters: FilterDefinitionByEntity<Person>[] = [
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'phone',
|
key: 'phone',
|
||||||
label: 'Phone',
|
label: 'Phone',
|
||||||
icon: <IconPhone size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconPhone size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'createdAt',
|
key: 'createdAt',
|
||||||
label: 'Created at',
|
label: 'Created at',
|
||||||
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconCalendarEvent size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'date',
|
type: 'date',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'city',
|
key: 'city',
|
||||||
label: 'City',
|
label: 'City',
|
||||||
icon: <IconMap size={icon.size.md} stroke={icon.stroke.sm} />,
|
icon: <IconMap size={icon.size.md} stroke={icon.stroke.sm} />,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { Activity } from '~/generated/graphql';
|
|||||||
|
|
||||||
export const tasksFilters: FilterDefinitionByEntity<Activity>[] = [
|
export const tasksFilters: FilterDefinitionByEntity<Activity>[] = [
|
||||||
{
|
{
|
||||||
field: 'assigneeId',
|
key: 'assigneeId',
|
||||||
label: 'Assignee',
|
label: 'Assignee',
|
||||||
icon: <IconUser />,
|
icon: <IconUser />,
|
||||||
type: 'entity',
|
type: 'entity',
|
||||||
|
|||||||
@ -3,47 +3,49 @@ import { Injectable } from '@nestjs/common';
|
|||||||
import { PureAbility, AbilityBuilder } from '@casl/ability';
|
import { PureAbility, AbilityBuilder } from '@casl/ability';
|
||||||
import { createPrismaAbility, PrismaQuery, Subjects } from '@casl/prisma';
|
import { createPrismaAbility, PrismaQuery, Subjects } from '@casl/prisma';
|
||||||
import {
|
import {
|
||||||
Attachment,
|
|
||||||
Activity,
|
Activity,
|
||||||
Company,
|
ActivityTarget,
|
||||||
|
Attachment,
|
||||||
Comment,
|
Comment,
|
||||||
|
Company,
|
||||||
|
Favorite,
|
||||||
Person,
|
Person,
|
||||||
|
Pipeline,
|
||||||
|
PipelineProgress,
|
||||||
|
PipelineStage,
|
||||||
RefreshToken,
|
RefreshToken,
|
||||||
User,
|
User,
|
||||||
Workspace,
|
|
||||||
WorkspaceMember,
|
|
||||||
ActivityTarget,
|
|
||||||
Pipeline,
|
|
||||||
PipelineStage,
|
|
||||||
PipelineProgress,
|
|
||||||
UserSettings,
|
UserSettings,
|
||||||
View,
|
View,
|
||||||
ViewField,
|
ViewField,
|
||||||
Favorite,
|
ViewFilter,
|
||||||
ViewSort,
|
ViewSort,
|
||||||
|
Workspace,
|
||||||
|
WorkspaceMember,
|
||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { AbilityAction } from './ability.action';
|
import { AbilityAction } from './ability.action';
|
||||||
|
|
||||||
type SubjectsAbility = Subjects<{
|
type SubjectsAbility = Subjects<{
|
||||||
User: User;
|
|
||||||
Workspace: Workspace;
|
|
||||||
WorkspaceMember: WorkspaceMember;
|
|
||||||
Company: Company;
|
|
||||||
Person: Person;
|
|
||||||
RefreshToken: RefreshToken;
|
|
||||||
Activity: Activity;
|
Activity: Activity;
|
||||||
Comment: Comment;
|
|
||||||
ActivityTarget: ActivityTarget;
|
ActivityTarget: ActivityTarget;
|
||||||
Pipeline: Pipeline;
|
|
||||||
PipelineStage: PipelineStage;
|
|
||||||
PipelineProgress: PipelineProgress;
|
|
||||||
Attachment: Attachment;
|
Attachment: Attachment;
|
||||||
|
Comment: Comment;
|
||||||
|
Company: Company;
|
||||||
|
Favorite: Favorite;
|
||||||
|
Person: Person;
|
||||||
|
Pipeline: Pipeline;
|
||||||
|
PipelineProgress: PipelineProgress;
|
||||||
|
PipelineStage: PipelineStage;
|
||||||
|
RefreshToken: RefreshToken;
|
||||||
|
User: User;
|
||||||
UserSettings: UserSettings;
|
UserSettings: UserSettings;
|
||||||
View: View;
|
View: View;
|
||||||
ViewField: ViewField;
|
ViewField: ViewField;
|
||||||
Favorite: Favorite;
|
ViewFilter: ViewFilter;
|
||||||
ViewSort: ViewSort;
|
ViewSort: ViewSort;
|
||||||
|
Workspace: Workspace;
|
||||||
|
WorkspaceMember: WorkspaceMember;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type AppAbility = PureAbility<
|
export type AppAbility = PureAbility<
|
||||||
@ -147,10 +149,11 @@ export class AbilityFactory {
|
|||||||
can(AbilityAction.Create, 'ViewField', { workspaceId: workspace.id });
|
can(AbilityAction.Create, 'ViewField', { workspaceId: workspace.id });
|
||||||
can(AbilityAction.Update, 'ViewField', { workspaceId: workspace.id });
|
can(AbilityAction.Update, 'ViewField', { workspaceId: workspace.id });
|
||||||
|
|
||||||
//Favorite
|
// ViewFilter
|
||||||
can(AbilityAction.Read, 'Favorite', { workspaceId: workspace.id });
|
can(AbilityAction.Read, 'ViewFilter', { workspaceId: workspace.id });
|
||||||
can(AbilityAction.Create, 'Favorite');
|
can(AbilityAction.Create, 'ViewFilter', { workspaceId: workspace.id });
|
||||||
can(AbilityAction.Delete, 'Favorite', { workspaceId: workspace.id });
|
can(AbilityAction.Update, 'ViewFilter', { workspaceId: workspace.id });
|
||||||
|
can(AbilityAction.Delete, 'ViewFilter', { workspaceId: workspace.id });
|
||||||
|
|
||||||
// ViewSort
|
// ViewSort
|
||||||
can(AbilityAction.Read, 'ViewSort', { workspaceId: workspace.id });
|
can(AbilityAction.Read, 'ViewSort', { workspaceId: workspace.id });
|
||||||
@ -158,6 +161,11 @@ export class AbilityFactory {
|
|||||||
can(AbilityAction.Update, 'ViewSort', { workspaceId: workspace.id });
|
can(AbilityAction.Update, 'ViewSort', { workspaceId: workspace.id });
|
||||||
can(AbilityAction.Delete, 'ViewSort', { workspaceId: workspace.id });
|
can(AbilityAction.Delete, 'ViewSort', { workspaceId: workspace.id });
|
||||||
|
|
||||||
|
// Favorite
|
||||||
|
can(AbilityAction.Read, 'Favorite', { workspaceId: workspace.id });
|
||||||
|
can(AbilityAction.Create, 'Favorite');
|
||||||
|
can(AbilityAction.Delete, 'Favorite', { workspaceId: workspace.id });
|
||||||
|
|
||||||
return build();
|
return build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -116,6 +116,12 @@ import {
|
|||||||
UpdateViewAbilityHandler,
|
UpdateViewAbilityHandler,
|
||||||
DeleteViewAbilityHandler,
|
DeleteViewAbilityHandler,
|
||||||
} from './handlers/view.ability-handler';
|
} from './handlers/view.ability-handler';
|
||||||
|
import {
|
||||||
|
CreateViewFilterAbilityHandler,
|
||||||
|
DeleteViewFilterAbilityHandler,
|
||||||
|
ReadViewFilterAbilityHandler,
|
||||||
|
UpdateViewFilterAbilityHandler,
|
||||||
|
} from './handlers/view-filter.ability-handler';
|
||||||
|
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
@ -213,6 +219,11 @@ import {
|
|||||||
ReadViewFieldAbilityHandler,
|
ReadViewFieldAbilityHandler,
|
||||||
CreateViewFieldAbilityHandler,
|
CreateViewFieldAbilityHandler,
|
||||||
UpdateViewFieldAbilityHandler,
|
UpdateViewFieldAbilityHandler,
|
||||||
|
// ViewFilter
|
||||||
|
ReadViewFilterAbilityHandler,
|
||||||
|
CreateViewFilterAbilityHandler,
|
||||||
|
UpdateViewFilterAbilityHandler,
|
||||||
|
DeleteViewFilterAbilityHandler,
|
||||||
// ViewSort
|
// ViewSort
|
||||||
ReadViewSortAbilityHandler,
|
ReadViewSortAbilityHandler,
|
||||||
CreateViewSortAbilityHandler,
|
CreateViewSortAbilityHandler,
|
||||||
@ -312,6 +323,11 @@ import {
|
|||||||
ReadViewFieldAbilityHandler,
|
ReadViewFieldAbilityHandler,
|
||||||
CreateViewFieldAbilityHandler,
|
CreateViewFieldAbilityHandler,
|
||||||
UpdateViewFieldAbilityHandler,
|
UpdateViewFieldAbilityHandler,
|
||||||
|
// ViewFilter
|
||||||
|
ReadViewFilterAbilityHandler,
|
||||||
|
CreateViewFilterAbilityHandler,
|
||||||
|
UpdateViewFilterAbilityHandler,
|
||||||
|
DeleteViewFilterAbilityHandler,
|
||||||
// ViewSort
|
// ViewSort
|
||||||
ReadViewSortAbilityHandler,
|
ReadViewSortAbilityHandler,
|
||||||
CreateViewSortAbilityHandler,
|
CreateViewSortAbilityHandler,
|
||||||
|
|||||||
122
server/src/ability/handlers/view-filter.ability-handler.ts
Normal file
122
server/src/ability/handlers/view-filter.ability-handler.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import {
|
||||||
|
ExecutionContext,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||||
|
|
||||||
|
import { subject } from '@casl/ability';
|
||||||
|
|
||||||
|
import { IAbilityHandler } from 'src/ability/interfaces/ability-handler.interface';
|
||||||
|
|
||||||
|
import { AbilityAction } from 'src/ability/ability.action';
|
||||||
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
|
import {
|
||||||
|
convertToWhereInput,
|
||||||
|
relationAbilityChecker,
|
||||||
|
} from 'src/ability/ability.util';
|
||||||
|
import { PrismaService } from 'src/database/prisma.service';
|
||||||
|
import { assert } from 'src/utils/assert';
|
||||||
|
import { ViewFilterWhereUniqueInput } from 'src/core/@generated/view-filter/view-filter-where-unique.input';
|
||||||
|
import { ViewFilterWhereInput } from 'src/core/@generated/view-filter/view-filter-where.input';
|
||||||
|
|
||||||
|
class ViewFilterArgs {
|
||||||
|
where?: ViewFilterWhereInput | ViewFilterWhereUniqueInput;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isViewFilterWhereUniqueInput = (
|
||||||
|
input: ViewFilterWhereInput | ViewFilterWhereUniqueInput,
|
||||||
|
): input is ViewFilterWhereUniqueInput => 'viewId_key' in input;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ReadViewFilterAbilityHandler implements IAbilityHandler {
|
||||||
|
handle(ability: AppAbility) {
|
||||||
|
return ability.can(AbilityAction.Read, 'ViewFilter');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CreateViewFilterAbilityHandler implements IAbilityHandler {
|
||||||
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs();
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'ViewFilter',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ability.can(AbilityAction.Create, 'ViewFilter');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UpdateViewFilterAbilityHandler implements IAbilityHandler {
|
||||||
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs<ViewFilterArgs>();
|
||||||
|
const viewFilter = await this.prismaService.client.viewFilter.findFirst({
|
||||||
|
where:
|
||||||
|
args.where && isViewFilterWhereUniqueInput(args.where)
|
||||||
|
? args.where.viewId_key
|
||||||
|
: args.where,
|
||||||
|
});
|
||||||
|
assert(viewFilter, '', NotFoundException);
|
||||||
|
|
||||||
|
const allowed = await relationAbilityChecker(
|
||||||
|
'ViewFilter',
|
||||||
|
ability,
|
||||||
|
this.prismaService.client,
|
||||||
|
args,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ability.can(AbilityAction.Update, subject('ViewFilter', viewFilter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DeleteViewFilterAbilityHandler implements IAbilityHandler {
|
||||||
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||||
|
const gqlContext = GqlExecutionContext.create(context);
|
||||||
|
const args = gqlContext.getArgs<ViewFilterArgs>();
|
||||||
|
const where = convertToWhereInput(
|
||||||
|
args.where && isViewFilterWhereUniqueInput(args.where)
|
||||||
|
? args.where.viewId_key
|
||||||
|
: args.where,
|
||||||
|
);
|
||||||
|
const viewFilters = await this.prismaService.client.viewFilter.findMany({
|
||||||
|
where,
|
||||||
|
});
|
||||||
|
assert(viewFilters.length, '', NotFoundException);
|
||||||
|
|
||||||
|
for (const viewFilter of viewFilters) {
|
||||||
|
const allowed = ability.can(
|
||||||
|
AbilityAction.Delete,
|
||||||
|
subject('ViewFilter', viewFilter),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
102
server/src/core/view/resolvers/view-filter.resolver.ts
Normal file
102
server/src/core/view/resolvers/view-filter.resolver.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import { UseGuards } from '@nestjs/common';
|
||||||
|
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||||
|
|
||||||
|
import { accessibleBy } from '@casl/prisma';
|
||||||
|
import { Prisma, Workspace } from '@prisma/client';
|
||||||
|
|
||||||
|
import { AppAbility } from 'src/ability/ability.factory';
|
||||||
|
import {
|
||||||
|
CreateViewFilterAbilityHandler,
|
||||||
|
DeleteViewFilterAbilityHandler,
|
||||||
|
ReadViewFilterAbilityHandler,
|
||||||
|
UpdateViewFilterAbilityHandler,
|
||||||
|
} from 'src/ability/handlers/view-filter.ability-handler';
|
||||||
|
import { FindManyViewFilterArgs } from 'src/core/@generated/view-filter/find-many-view-filter.args';
|
||||||
|
import { ViewFilter } from 'src/core/@generated/view-filter/view-filter.model';
|
||||||
|
import { ViewFilterService } from 'src/core/view/services/view-filter.service';
|
||||||
|
import { CheckAbilities } from 'src/decorators/check-abilities.decorator';
|
||||||
|
import {
|
||||||
|
PrismaSelect,
|
||||||
|
PrismaSelector,
|
||||||
|
} from 'src/decorators/prisma-select.decorator';
|
||||||
|
import { UserAbility } from 'src/decorators/user-ability.decorator';
|
||||||
|
import { AbilityGuard } from 'src/guards/ability.guard';
|
||||||
|
import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
||||||
|
import { UpdateOneViewFilterArgs } from 'src/core/@generated/view-filter/update-one-view-filter.args';
|
||||||
|
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||||
|
import { AffectedRows } from 'src/core/@generated/prisma/affected-rows.output';
|
||||||
|
import { DeleteManyViewFilterArgs } from 'src/core/@generated/view-filter/delete-many-view-filter.args';
|
||||||
|
import { CreateManyViewFilterArgs } from 'src/core/@generated/view-filter/create-many-view-filter.args';
|
||||||
|
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Resolver(() => ViewFilter)
|
||||||
|
export class ViewFilterResolver {
|
||||||
|
constructor(private readonly viewFilterService: ViewFilterService) {}
|
||||||
|
|
||||||
|
@Mutation(() => AffectedRows)
|
||||||
|
@UseGuards(AbilityGuard)
|
||||||
|
@CheckAbilities(CreateViewFilterAbilityHandler)
|
||||||
|
async createManyViewFilter(
|
||||||
|
@Args() args: CreateManyViewFilterArgs,
|
||||||
|
@AuthWorkspace() workspace: Workspace,
|
||||||
|
): Promise<AffectedRows> {
|
||||||
|
return this.viewFilterService.createMany({
|
||||||
|
data: args.data.map((data) => ({
|
||||||
|
...data,
|
||||||
|
workspaceId: workspace.id,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Query(() => [ViewFilter])
|
||||||
|
@UseGuards(AbilityGuard)
|
||||||
|
@CheckAbilities(ReadViewFilterAbilityHandler)
|
||||||
|
async findManyViewFilter(
|
||||||
|
@Args() args: FindManyViewFilterArgs,
|
||||||
|
@UserAbility() ability: AppAbility,
|
||||||
|
@PrismaSelector({ modelName: 'ViewFilter' })
|
||||||
|
prismaSelect: PrismaSelect<'ViewFilter'>,
|
||||||
|
): Promise<Partial<ViewFilter>[]> {
|
||||||
|
return this.viewFilterService.findMany({
|
||||||
|
where: args.where
|
||||||
|
? {
|
||||||
|
AND: [args.where, accessibleBy(ability).ViewFilter],
|
||||||
|
}
|
||||||
|
: accessibleBy(ability).ViewFilter,
|
||||||
|
orderBy: args.orderBy,
|
||||||
|
cursor: args.cursor,
|
||||||
|
take: args.take,
|
||||||
|
skip: args.skip,
|
||||||
|
distinct: args.distinct,
|
||||||
|
select: prismaSelect.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => ViewFilter)
|
||||||
|
@UseGuards(AbilityGuard)
|
||||||
|
@CheckAbilities(UpdateViewFilterAbilityHandler)
|
||||||
|
async updateOneViewFilter(
|
||||||
|
@Args() args: UpdateOneViewFilterArgs,
|
||||||
|
@PrismaSelector({ modelName: 'ViewFilter' })
|
||||||
|
prismaSelect: PrismaSelect<'ViewFilter'>,
|
||||||
|
): Promise<Partial<ViewFilter>> {
|
||||||
|
return this.viewFilterService.update({
|
||||||
|
data: args.data,
|
||||||
|
where: args.where,
|
||||||
|
select: prismaSelect.value,
|
||||||
|
} as Prisma.ViewFilterUpdateArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mutation(() => AffectedRows, {
|
||||||
|
nullable: false,
|
||||||
|
})
|
||||||
|
@UseGuards(AbilityGuard)
|
||||||
|
@CheckAbilities(DeleteViewFilterAbilityHandler)
|
||||||
|
async deleteManyViewFilter(
|
||||||
|
@Args() args: DeleteManyViewFilterArgs,
|
||||||
|
): Promise<AffectedRows> {
|
||||||
|
return this.viewFilterService.deleteMany({
|
||||||
|
where: args.where,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
39
server/src/core/view/services/view-filter.service.ts
Normal file
39
server/src/core/view/services/view-filter.service.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { PrismaService } from 'src/database/prisma.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ViewFilterService {
|
||||||
|
constructor(private readonly prismaService: PrismaService) {}
|
||||||
|
|
||||||
|
// Find
|
||||||
|
findFirst = this.prismaService.client.viewFilter.findFirst;
|
||||||
|
findFirstOrThrow = this.prismaService.client.viewFilter.findFirstOrThrow;
|
||||||
|
|
||||||
|
findUnique = this.prismaService.client.viewFilter.findUnique;
|
||||||
|
findUniqueOrThrow = this.prismaService.client.viewFilter.findUniqueOrThrow;
|
||||||
|
|
||||||
|
findMany = this.prismaService.client.viewFilter.findMany;
|
||||||
|
|
||||||
|
// Create
|
||||||
|
create = this.prismaService.client.viewFilter.create;
|
||||||
|
createMany = this.prismaService.client.viewFilter.createMany;
|
||||||
|
|
||||||
|
// Update
|
||||||
|
update = this.prismaService.client.viewFilter.update;
|
||||||
|
upsert = this.prismaService.client.viewFilter.upsert;
|
||||||
|
updateMany = this.prismaService.client.viewFilter.updateMany;
|
||||||
|
|
||||||
|
// Delete
|
||||||
|
delete = this.prismaService.client.viewFilter.delete;
|
||||||
|
deleteMany = this.prismaService.client.viewFilter.deleteMany;
|
||||||
|
|
||||||
|
// Aggregate
|
||||||
|
aggregate = this.prismaService.client.viewFilter.aggregate;
|
||||||
|
|
||||||
|
// Count
|
||||||
|
count = this.prismaService.client.viewFilter.count;
|
||||||
|
|
||||||
|
// GroupBy
|
||||||
|
groupBy = this.prismaService.client.viewFilter.groupBy;
|
||||||
|
}
|
||||||
@ -6,14 +6,18 @@ import { ViewSortService } from './services/view-sort.service';
|
|||||||
import { ViewSortResolver } from './resolvers/view-sort.resolver';
|
import { ViewSortResolver } from './resolvers/view-sort.resolver';
|
||||||
import { ViewService } from './services/view.service';
|
import { ViewService } from './services/view.service';
|
||||||
import { ViewResolver } from './resolvers/view.resolver';
|
import { ViewResolver } from './resolvers/view.resolver';
|
||||||
|
import { ViewFilterService } from './services/view-filter.service';
|
||||||
|
import { ViewFilterResolver } from './resolvers/view-filter.resolver';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
providers: [
|
providers: [
|
||||||
ViewService,
|
ViewService,
|
||||||
ViewFieldService,
|
ViewFieldService,
|
||||||
|
ViewFilterService,
|
||||||
ViewSortService,
|
ViewSortService,
|
||||||
ViewResolver,
|
ViewResolver,
|
||||||
ViewFieldResolver,
|
ViewFieldResolver,
|
||||||
|
ViewFilterResolver,
|
||||||
ViewSortResolver,
|
ViewSortResolver,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -112,8 +112,6 @@ export class WorkspaceService {
|
|||||||
activityTarget,
|
activityTarget,
|
||||||
activity,
|
activity,
|
||||||
view,
|
view,
|
||||||
viewField,
|
|
||||||
viewSort,
|
|
||||||
} = this.prismaService.client;
|
} = this.prismaService.client;
|
||||||
|
|
||||||
const activitys = await activity.findMany({
|
const activitys = await activity.findMany({
|
||||||
@ -156,12 +154,6 @@ export class WorkspaceService {
|
|||||||
view.deleteMany({
|
view.deleteMany({
|
||||||
where,
|
where,
|
||||||
}),
|
}),
|
||||||
viewField.deleteMany({
|
|
||||||
where,
|
|
||||||
}),
|
|
||||||
viewSort.deleteMany({
|
|
||||||
where,
|
|
||||||
}),
|
|
||||||
refreshToken.deleteMany({
|
refreshToken.deleteMany({
|
||||||
where: { userId },
|
where: { userId },
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "ViewFilterOperand" AS ENUM ('Contains', 'DoesNotContain', 'GreaterThan', 'LessThan', 'Is', 'IsNot');
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "viewFilters" (
|
||||||
|
"displayValue" TEXT NOT NULL,
|
||||||
|
"key" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"operand" "ViewFilterOperand" NOT NULL,
|
||||||
|
"value" TEXT NOT NULL,
|
||||||
|
"viewId" TEXT NOT NULL,
|
||||||
|
"workspaceId" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "viewFilters_pkey" PRIMARY KEY ("viewId","key")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "viewFilters" ADD CONSTRAINT "viewFilters_viewId_fkey" FOREIGN KEY ("viewId") REFERENCES "views"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "viewFilters" ADD CONSTRAINT "viewFilters_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
@ -174,6 +174,7 @@ model Workspace {
|
|||||||
pipelineProgresses PipelineProgress[]
|
pipelineProgresses PipelineProgress[]
|
||||||
activityTargets ActivityTarget[]
|
activityTargets ActivityTarget[]
|
||||||
viewFields ViewField[]
|
viewFields ViewField[]
|
||||||
|
viewFilters ViewFilter[]
|
||||||
views View[]
|
views View[]
|
||||||
viewSorts ViewSort[]
|
viewSorts ViewSort[]
|
||||||
|
|
||||||
@ -582,6 +583,7 @@ model View {
|
|||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
|
|
||||||
fields ViewField[]
|
fields ViewField[]
|
||||||
|
filters ViewFilter[]
|
||||||
name String
|
name String
|
||||||
objectId String
|
objectId String
|
||||||
sorts ViewSort[]
|
sorts ViewSort[]
|
||||||
@ -596,6 +598,34 @@ model View {
|
|||||||
@@map("views")
|
@@map("views")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ViewFilterOperand {
|
||||||
|
Contains
|
||||||
|
DoesNotContain
|
||||||
|
GreaterThan
|
||||||
|
LessThan
|
||||||
|
Is
|
||||||
|
IsNot
|
||||||
|
}
|
||||||
|
|
||||||
|
model ViewFilter {
|
||||||
|
displayValue String
|
||||||
|
key String
|
||||||
|
name String
|
||||||
|
operand ViewFilterOperand
|
||||||
|
value String
|
||||||
|
|
||||||
|
view View @relation(fields: [viewId], references: [id], onDelete: Cascade)
|
||||||
|
viewId String
|
||||||
|
|
||||||
|
/// @TypeGraphQL.omit(input: true, output: true)
|
||||||
|
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||||
|
/// @TypeGraphQL.omit(input: true, output: true)
|
||||||
|
workspaceId String
|
||||||
|
|
||||||
|
@@id([viewId, key])
|
||||||
|
@@map("viewFilters")
|
||||||
|
}
|
||||||
|
|
||||||
enum ViewSortDirection {
|
enum ViewSortDirection {
|
||||||
asc
|
asc
|
||||||
desc
|
desc
|
||||||
|
|||||||
@ -18,6 +18,7 @@ export type ModelSelectMap = {
|
|||||||
Attachment: Prisma.AttachmentSelect;
|
Attachment: Prisma.AttachmentSelect;
|
||||||
Favorite: Prisma.FavoriteSelect;
|
Favorite: Prisma.FavoriteSelect;
|
||||||
View: Prisma.ViewSelect;
|
View: Prisma.ViewSelect;
|
||||||
|
ViewFilter: Prisma.ViewFilterSelect;
|
||||||
ViewSort: Prisma.ViewSortSelect;
|
ViewSort: Prisma.ViewSortSelect;
|
||||||
ViewField: Prisma.ViewFieldSelect;
|
ViewField: Prisma.ViewFieldSelect;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user