mirror of
https://github.com/twentyhq/twenty.git
synced 2024-12-18 17:12:53 +03:00
Merge commit '80a562d90d1d354c580351a2c94d32aa024b139e' into context-menu-vertical
This commit is contained in:
commit
807506549a
@ -22,7 +22,7 @@ Upon restart, a powershell window will open and install Ubuntu. This may take a
|
||||
You will be prompted to create a username and password for your Ubuntu installation.
|
||||
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<img src="/img/developer/ide-start-dev-container.png" alt="Visual Studio Code: Open in container" width="90%" />
|
||||
<img src="/img/developer/wsl-complete.png" alt="Visual Studio Code: Open in container" width="90%" />
|
||||
</div>
|
||||
|
||||
## Setup your developer environment
|
@ -846,6 +846,20 @@ export type EnumPipelineProgressableTypeFilter = {
|
||||
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
||||
};
|
||||
|
||||
export type EnumViewSortDirectionFilter = {
|
||||
equals?: InputMaybe<ViewSortDirection>;
|
||||
in?: InputMaybe<Array<ViewSortDirection>>;
|
||||
not?: InputMaybe<NestedEnumViewSortDirectionFilter>;
|
||||
notIn?: InputMaybe<Array<ViewSortDirection>>;
|
||||
};
|
||||
|
||||
export type EnumViewTypeFilter = {
|
||||
equals?: InputMaybe<ViewType>;
|
||||
in?: InputMaybe<Array<ViewType>>;
|
||||
not?: InputMaybe<NestedEnumViewTypeFilter>;
|
||||
notIn?: InputMaybe<Array<ViewType>>;
|
||||
};
|
||||
|
||||
export enum FileFolder {
|
||||
Attachment = 'Attachment',
|
||||
PersonPicture = 'PersonPicture',
|
||||
@ -902,6 +916,7 @@ export type Mutation = {
|
||||
challenge: LoginToken;
|
||||
createEvent: Analytics;
|
||||
createManyViewField: AffectedRows;
|
||||
createManyViewSort: AffectedRows;
|
||||
createOneActivity: Activity;
|
||||
createOneComment: Comment;
|
||||
createOneCompany: Company;
|
||||
@ -913,6 +928,7 @@ export type Mutation = {
|
||||
deleteManyCompany: AffectedRows;
|
||||
deleteManyPerson: AffectedRows;
|
||||
deleteManyPipelineProgress: AffectedRows;
|
||||
deleteManyViewSort: AffectedRows;
|
||||
deleteUserAccount: User;
|
||||
deleteWorkspaceMember: WorkspaceMember;
|
||||
impersonate: Verify;
|
||||
@ -924,6 +940,7 @@ export type Mutation = {
|
||||
updateOnePipelineProgress?: Maybe<PipelineProgress>;
|
||||
updateOnePipelineStage?: Maybe<PipelineStage>;
|
||||
updateOneViewField: ViewField;
|
||||
updateOneViewSort: ViewSort;
|
||||
updateUser: User;
|
||||
updateWorkspace: Workspace;
|
||||
uploadAttachment: Scalars['String'];
|
||||
@ -959,6 +976,12 @@ export type MutationCreateManyViewFieldArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateManyViewSortArgs = {
|
||||
data: Array<ViewSortCreateManyInput>;
|
||||
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneActivityArgs = {
|
||||
data: ActivityCreateInput;
|
||||
};
|
||||
@ -1009,6 +1032,11 @@ export type MutationDeleteManyPipelineProgressArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteManyViewSortArgs = {
|
||||
where?: InputMaybe<ViewSortWhereInput>;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeleteWorkspaceMemberArgs = {
|
||||
where: WorkspaceMemberWhereUniqueInput;
|
||||
};
|
||||
@ -1067,6 +1095,12 @@ export type MutationUpdateOneViewFieldArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateOneViewSortArgs = {
|
||||
data: ViewSortUpdateInput;
|
||||
where: ViewSortWhereUniqueInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateUserArgs = {
|
||||
data: UserUpdateInput;
|
||||
where: UserWhereUniqueInput;
|
||||
@ -1178,6 +1212,20 @@ export type NestedEnumPipelineProgressableTypeFilter = {
|
||||
notIn?: InputMaybe<Array<PipelineProgressableType>>;
|
||||
};
|
||||
|
||||
export type NestedEnumViewSortDirectionFilter = {
|
||||
equals?: InputMaybe<ViewSortDirection>;
|
||||
in?: InputMaybe<Array<ViewSortDirection>>;
|
||||
not?: InputMaybe<NestedEnumViewSortDirectionFilter>;
|
||||
notIn?: InputMaybe<Array<ViewSortDirection>>;
|
||||
};
|
||||
|
||||
export type NestedEnumViewTypeFilter = {
|
||||
equals?: InputMaybe<ViewType>;
|
||||
in?: InputMaybe<Array<ViewType>>;
|
||||
not?: InputMaybe<NestedEnumViewTypeFilter>;
|
||||
notIn?: InputMaybe<Array<ViewType>>;
|
||||
};
|
||||
|
||||
export type NestedIntFilter = {
|
||||
equals?: InputMaybe<Scalars['Int']>;
|
||||
gt?: InputMaybe<Scalars['Int']>;
|
||||
@ -1766,6 +1814,7 @@ export type Query = {
|
||||
findManyPipelineStage: Array<PipelineStage>;
|
||||
findManyUser: Array<User>;
|
||||
findManyViewField: Array<ViewField>;
|
||||
findManyViewSort: Array<ViewSort>;
|
||||
findManyWorkspaceMember: Array<WorkspaceMember>;
|
||||
findUniqueCompany: Company;
|
||||
findUniquePerson: Person;
|
||||
@ -1863,6 +1912,16 @@ export type QueryFindManyViewFieldArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type QueryFindManyViewSortArgs = {
|
||||
cursor?: InputMaybe<ViewSortWhereUniqueInput>;
|
||||
distinct?: InputMaybe<Array<ViewSortScalarFieldEnum>>;
|
||||
orderBy?: InputMaybe<Array<ViewSortOrderByWithRelationInput>>;
|
||||
skip?: InputMaybe<Scalars['Int']>;
|
||||
take?: InputMaybe<Scalars['Int']>;
|
||||
where?: InputMaybe<ViewSortWhereInput>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryFindManyWorkspaceMemberArgs = {
|
||||
cursor?: InputMaybe<WorkspaceMemberWhereUniqueInput>;
|
||||
distinct?: InputMaybe<Array<WorkspaceMemberScalarFieldEnum>>;
|
||||
@ -2161,6 +2220,20 @@ export type Verify = {
|
||||
user: User;
|
||||
};
|
||||
|
||||
export type View = {
|
||||
__typename?: 'View';
|
||||
fields?: Maybe<Array<ViewField>>;
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
objectId: Scalars['String'];
|
||||
sorts?: Maybe<Array<ViewSort>>;
|
||||
type: ViewType;
|
||||
};
|
||||
|
||||
export type ViewCreateNestedOneWithoutFieldsInput = {
|
||||
connect?: InputMaybe<ViewWhereUniqueInput>;
|
||||
};
|
||||
|
||||
export type ViewField = {
|
||||
__typename?: 'ViewField';
|
||||
fieldName: Scalars['String'];
|
||||
@ -2169,6 +2242,8 @@ export type ViewField = {
|
||||
isVisible: Scalars['Boolean'];
|
||||
objectName: Scalars['String'];
|
||||
sizeInPx: Scalars['Int'];
|
||||
view?: Maybe<View>;
|
||||
viewId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ViewFieldCreateInput = {
|
||||
@ -2178,6 +2253,7 @@ export type ViewFieldCreateInput = {
|
||||
isVisible: Scalars['Boolean'];
|
||||
objectName: Scalars['String'];
|
||||
sizeInPx: Scalars['Int'];
|
||||
view?: InputMaybe<ViewCreateNestedOneWithoutFieldsInput>;
|
||||
};
|
||||
|
||||
export type ViewFieldCreateManyInput = {
|
||||
@ -2187,6 +2263,17 @@ export type ViewFieldCreateManyInput = {
|
||||
isVisible: Scalars['Boolean'];
|
||||
objectName: Scalars['String'];
|
||||
sizeInPx: Scalars['Int'];
|
||||
viewId?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ViewFieldListRelationFilter = {
|
||||
every?: InputMaybe<ViewFieldWhereInput>;
|
||||
none?: InputMaybe<ViewFieldWhereInput>;
|
||||
some?: InputMaybe<ViewFieldWhereInput>;
|
||||
};
|
||||
|
||||
export type ViewFieldOrderByRelationAggregateInput = {
|
||||
_count?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
export type ViewFieldOrderByWithRelationInput = {
|
||||
@ -2196,6 +2283,8 @@ export type ViewFieldOrderByWithRelationInput = {
|
||||
isVisible?: InputMaybe<SortOrder>;
|
||||
objectName?: InputMaybe<SortOrder>;
|
||||
sizeInPx?: InputMaybe<SortOrder>;
|
||||
view?: InputMaybe<ViewOrderByWithRelationInput>;
|
||||
viewId?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
export enum ViewFieldScalarFieldEnum {
|
||||
@ -2205,6 +2294,7 @@ export enum ViewFieldScalarFieldEnum {
|
||||
IsVisible = 'isVisible',
|
||||
ObjectName = 'objectName',
|
||||
SizeInPx = 'sizeInPx',
|
||||
ViewId = 'viewId',
|
||||
WorkspaceId = 'workspaceId'
|
||||
}
|
||||
|
||||
@ -2215,6 +2305,7 @@ export type ViewFieldUpdateInput = {
|
||||
isVisible?: InputMaybe<Scalars['Boolean']>;
|
||||
objectName?: InputMaybe<Scalars['String']>;
|
||||
sizeInPx?: InputMaybe<Scalars['Int']>;
|
||||
view?: InputMaybe<ViewUpdateOneWithoutFieldsNestedInput>;
|
||||
};
|
||||
|
||||
export type ViewFieldUpdateManyWithoutWorkspaceNestedInput = {
|
||||
@ -2233,10 +2324,156 @@ export type ViewFieldWhereInput = {
|
||||
isVisible?: InputMaybe<BoolFilter>;
|
||||
objectName?: InputMaybe<StringFilter>;
|
||||
sizeInPx?: InputMaybe<IntFilter>;
|
||||
view?: InputMaybe<ViewRelationFilter>;
|
||||
viewId?: InputMaybe<StringNullableFilter>;
|
||||
};
|
||||
|
||||
export type ViewFieldWhereUniqueInput = {
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
workspaceId_viewId_objectName_fieldName?: InputMaybe<ViewFieldWorkspaceIdViewIdObjectNameFieldNameCompoundUniqueInput>;
|
||||
};
|
||||
|
||||
export type ViewFieldWorkspaceIdViewIdObjectNameFieldNameCompoundUniqueInput = {
|
||||
fieldName: Scalars['String'];
|
||||
objectName: Scalars['String'];
|
||||
viewId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ViewOrderByWithRelationInput = {
|
||||
fields?: InputMaybe<ViewFieldOrderByRelationAggregateInput>;
|
||||
id?: InputMaybe<SortOrder>;
|
||||
name?: InputMaybe<SortOrder>;
|
||||
objectId?: InputMaybe<SortOrder>;
|
||||
sorts?: InputMaybe<ViewSortOrderByRelationAggregateInput>;
|
||||
type?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
export type ViewRelationFilter = {
|
||||
is?: InputMaybe<ViewWhereInput>;
|
||||
isNot?: InputMaybe<ViewWhereInput>;
|
||||
};
|
||||
|
||||
export type ViewSort = {
|
||||
__typename?: 'ViewSort';
|
||||
direction: ViewSortDirection;
|
||||
key: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
view: View;
|
||||
viewId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ViewSortCreateManyInput = {
|
||||
direction: ViewSortDirection;
|
||||
key: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
viewId: Scalars['String'];
|
||||
};
|
||||
|
||||
export enum ViewSortDirection {
|
||||
Asc = 'asc',
|
||||
Desc = 'desc'
|
||||
}
|
||||
|
||||
export type ViewSortListRelationFilter = {
|
||||
every?: InputMaybe<ViewSortWhereInput>;
|
||||
none?: InputMaybe<ViewSortWhereInput>;
|
||||
some?: InputMaybe<ViewSortWhereInput>;
|
||||
};
|
||||
|
||||
export type ViewSortOrderByRelationAggregateInput = {
|
||||
_count?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
export type ViewSortOrderByWithRelationInput = {
|
||||
direction?: InputMaybe<SortOrder>;
|
||||
key?: InputMaybe<SortOrder>;
|
||||
name?: InputMaybe<SortOrder>;
|
||||
view?: InputMaybe<ViewOrderByWithRelationInput>;
|
||||
viewId?: InputMaybe<SortOrder>;
|
||||
};
|
||||
|
||||
export enum ViewSortScalarFieldEnum {
|
||||
Direction = 'direction',
|
||||
Key = 'key',
|
||||
Name = 'name',
|
||||
ViewId = 'viewId',
|
||||
WorkspaceId = 'workspaceId'
|
||||
}
|
||||
|
||||
export type ViewSortUpdateInput = {
|
||||
direction?: InputMaybe<ViewSortDirection>;
|
||||
key?: InputMaybe<Scalars['String']>;
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
view?: InputMaybe<ViewUpdateOneRequiredWithoutSortsNestedInput>;
|
||||
};
|
||||
|
||||
export type ViewSortUpdateManyWithoutWorkspaceNestedInput = {
|
||||
connect?: InputMaybe<Array<ViewSortWhereUniqueInput>>;
|
||||
disconnect?: InputMaybe<Array<ViewSortWhereUniqueInput>>;
|
||||
set?: InputMaybe<Array<ViewSortWhereUniqueInput>>;
|
||||
};
|
||||
|
||||
export type ViewSortViewIdKeyCompoundUniqueInput = {
|
||||
key: Scalars['String'];
|
||||
viewId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type ViewSortWhereInput = {
|
||||
AND?: InputMaybe<Array<ViewSortWhereInput>>;
|
||||
NOT?: InputMaybe<Array<ViewSortWhereInput>>;
|
||||
OR?: InputMaybe<Array<ViewSortWhereInput>>;
|
||||
direction?: InputMaybe<EnumViewSortDirectionFilter>;
|
||||
key?: InputMaybe<StringFilter>;
|
||||
name?: InputMaybe<StringFilter>;
|
||||
view?: InputMaybe<ViewRelationFilter>;
|
||||
viewId?: InputMaybe<StringFilter>;
|
||||
};
|
||||
|
||||
export type ViewSortWhereUniqueInput = {
|
||||
viewId_key?: InputMaybe<ViewSortViewIdKeyCompoundUniqueInput>;
|
||||
};
|
||||
|
||||
export enum ViewType {
|
||||
Pipeline = 'Pipeline',
|
||||
Table = 'Table'
|
||||
}
|
||||
|
||||
export type ViewUpdateManyWithoutWorkspaceNestedInput = {
|
||||
connect?: InputMaybe<Array<ViewWhereUniqueInput>>;
|
||||
disconnect?: InputMaybe<Array<ViewWhereUniqueInput>>;
|
||||
set?: InputMaybe<Array<ViewWhereUniqueInput>>;
|
||||
};
|
||||
|
||||
export type ViewUpdateOneRequiredWithoutSortsNestedInput = {
|
||||
connect?: InputMaybe<ViewWhereUniqueInput>;
|
||||
};
|
||||
|
||||
export type ViewUpdateOneWithoutFieldsNestedInput = {
|
||||
connect?: InputMaybe<ViewWhereUniqueInput>;
|
||||
disconnect?: InputMaybe<Scalars['Boolean']>;
|
||||
};
|
||||
|
||||
export type ViewWhereInput = {
|
||||
AND?: InputMaybe<Array<ViewWhereInput>>;
|
||||
NOT?: InputMaybe<Array<ViewWhereInput>>;
|
||||
OR?: InputMaybe<Array<ViewWhereInput>>;
|
||||
fields?: InputMaybe<ViewFieldListRelationFilter>;
|
||||
id?: InputMaybe<StringFilter>;
|
||||
name?: InputMaybe<StringFilter>;
|
||||
objectId?: InputMaybe<StringFilter>;
|
||||
sorts?: InputMaybe<ViewSortListRelationFilter>;
|
||||
type?: InputMaybe<EnumViewTypeFilter>;
|
||||
};
|
||||
|
||||
export type ViewWhereUniqueInput = {
|
||||
id?: InputMaybe<Scalars['String']>;
|
||||
workspaceId_type_objectId_name?: InputMaybe<ViewWorkspaceIdTypeObjectIdNameCompoundUniqueInput>;
|
||||
};
|
||||
|
||||
export type ViewWorkspaceIdTypeObjectIdNameCompoundUniqueInput = {
|
||||
name: Scalars['String'];
|
||||
objectId: Scalars['String'];
|
||||
type: ViewType;
|
||||
};
|
||||
|
||||
export type Workspace = {
|
||||
@ -2258,6 +2495,8 @@ export type Workspace = {
|
||||
pipelines?: Maybe<Array<Pipeline>>;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
viewFields?: Maybe<Array<ViewField>>;
|
||||
viewSorts?: Maybe<Array<ViewSort>>;
|
||||
views?: Maybe<Array<View>>;
|
||||
workspaceMember?: Maybe<Array<WorkspaceMember>>;
|
||||
};
|
||||
|
||||
@ -2337,6 +2576,8 @@ export type WorkspaceUpdateInput = {
|
||||
pipelines?: InputMaybe<PipelineUpdateManyWithoutWorkspaceNestedInput>;
|
||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||
viewFields?: InputMaybe<ViewFieldUpdateManyWithoutWorkspaceNestedInput>;
|
||||
viewSorts?: InputMaybe<ViewSortUpdateManyWithoutWorkspaceNestedInput>;
|
||||
views?: InputMaybe<ViewUpdateManyWithoutWorkspaceNestedInput>;
|
||||
workspaceMember?: InputMaybe<WorkspaceMemberUpdateManyWithoutWorkspaceNestedInput>;
|
||||
};
|
||||
|
||||
@ -2503,12 +2744,14 @@ export type UpdateOneCompanyMutationVariables = Exact<{
|
||||
|
||||
export type UpdateOneCompanyMutation = { __typename?: 'Mutation', updateOneCompany?: { __typename?: 'Company', address: string, createdAt: string, domainName: string, employees?: number | null, linkedinUrl?: string | null, id: string, name: string, accountOwner?: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null } | null } | null };
|
||||
|
||||
export type InsertCompanyFragmentFragment = { __typename?: 'Company', domainName: string, address: string, id: string, name: string, createdAt: string };
|
||||
|
||||
export type InsertOneCompanyMutationVariables = Exact<{
|
||||
data: CompanyCreateInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type InsertOneCompanyMutation = { __typename?: 'Mutation', createOneCompany: { __typename?: 'Company', address: string, createdAt: string, domainName: string, linkedinUrl?: string | null, employees?: number | null, id: string, name: string } };
|
||||
export type InsertOneCompanyMutation = { __typename?: 'Mutation', createOneCompany: { __typename?: 'Company', domainName: string, address: string, id: string, name: string, createdAt: string } };
|
||||
|
||||
export type DeleteManyCompaniesMutationVariables = Exact<{
|
||||
ids?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
|
||||
@ -2590,12 +2833,14 @@ export type UpdateOnePersonMutationVariables = Exact<{
|
||||
|
||||
export type UpdateOnePersonMutation = { __typename?: 'Mutation', updateOnePerson?: { __typename?: 'Person', id: string, city?: string | null, email?: string | null, jobTitle?: string | null, linkedinUrl?: string | null, xUrl?: string | null, firstName?: string | null, lastName?: string | null, displayName: string, phone?: string | null, createdAt: string, company?: { __typename?: 'Company', domainName: string, name: string, id: string } | null } | null };
|
||||
|
||||
export type InsertPersonFragmentFragment = { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, displayName: string, createdAt: string };
|
||||
|
||||
export type InsertOnePersonMutationVariables = Exact<{
|
||||
data: PersonCreateInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type InsertOnePersonMutation = { __typename?: 'Mutation', createOnePerson: { __typename?: 'Person', id: string, city?: string | null, email?: string | null, firstName?: string | null, lastName?: string | null, jobTitle?: string | null, linkedinUrl?: string | null, xUrl?: string | null, displayName: string, phone?: string | null, createdAt: string, company?: { __typename?: 'Company', domainName: string, name: string, id: string } | null } };
|
||||
export type InsertOnePersonMutation = { __typename?: 'Mutation', createOnePerson: { __typename?: 'Person', id: string, firstName?: string | null, lastName?: string | null, displayName: string, createdAt: string } };
|
||||
|
||||
export type DeleteManyPersonMutationVariables = Exact<{
|
||||
ids?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;
|
||||
@ -2774,6 +3019,20 @@ export type CreateViewFieldsMutationVariables = Exact<{
|
||||
|
||||
export type CreateViewFieldsMutation = { __typename?: 'Mutation', createManyViewField: { __typename?: 'AffectedRows', count: number } };
|
||||
|
||||
export type CreateViewSortsMutationVariables = Exact<{
|
||||
data: Array<ViewSortCreateManyInput> | ViewSortCreateManyInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateViewSortsMutation = { __typename?: 'Mutation', createManyViewSort: { __typename?: 'AffectedRows', count: number } };
|
||||
|
||||
export type DeleteViewSortsMutationVariables = Exact<{
|
||||
where: ViewSortWhereInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type DeleteViewSortsMutation = { __typename?: 'Mutation', deleteManyViewSort: { __typename?: 'AffectedRows', count: number } };
|
||||
|
||||
export type GetViewFieldsQueryVariables = Exact<{
|
||||
where?: InputMaybe<ViewFieldWhereInput>;
|
||||
orderBy?: InputMaybe<Array<ViewFieldOrderByWithRelationInput> | ViewFieldOrderByWithRelationInput>;
|
||||
@ -2782,6 +3041,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 GetViewSortsQueryVariables = Exact<{
|
||||
where?: InputMaybe<ViewSortWhereInput>;
|
||||
}>;
|
||||
|
||||
|
||||
export type GetViewSortsQuery = { __typename?: 'Query', viewSorts: Array<{ __typename?: 'ViewSort', direction: ViewSortDirection, key: string, name: string }> };
|
||||
|
||||
export type UpdateViewFieldMutationVariables = Exact<{
|
||||
data: ViewFieldUpdateInput;
|
||||
where: ViewFieldWhereUniqueInput;
|
||||
@ -2790,6 +3056,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 UpdateViewSortMutationVariables = Exact<{
|
||||
data: ViewSortUpdateInput;
|
||||
where: ViewSortWhereUniqueInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateViewSortMutation = { __typename?: 'Mutation', viewSort: { __typename?: 'ViewSort', direction: ViewSortDirection, key: string, name: string } };
|
||||
|
||||
export type GetWorkspaceMembersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
@ -2849,6 +3123,24 @@ export const ActivityUpdatePartsFragmentDoc = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const InsertCompanyFragmentFragmentDoc = gql`
|
||||
fragment InsertCompanyFragment on Company {
|
||||
domainName
|
||||
address
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
}
|
||||
`;
|
||||
export const InsertPersonFragmentFragmentDoc = gql`
|
||||
fragment InsertPersonFragment on Person {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
displayName
|
||||
createdAt
|
||||
}
|
||||
`;
|
||||
export const CreateCommentDocument = gql`
|
||||
mutation CreateComment($commentId: String!, $commentText: String!, $authorId: String!, $activityId: String!, $createdAt: DateTime!) {
|
||||
createOneComment(
|
||||
@ -3886,16 +4178,10 @@ export type UpdateOneCompanyMutationOptions = Apollo.BaseMutationOptions<UpdateO
|
||||
export const InsertOneCompanyDocument = gql`
|
||||
mutation InsertOneCompany($data: CompanyCreateInput!) {
|
||||
createOneCompany(data: $data) {
|
||||
address
|
||||
createdAt
|
||||
domainName
|
||||
linkedinUrl
|
||||
employees
|
||||
id
|
||||
name
|
||||
...InsertCompanyFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
${InsertCompanyFragmentFragmentDoc}`;
|
||||
export type InsertOneCompanyMutationFn = Apollo.MutationFunction<InsertOneCompanyMutation, InsertOneCompanyMutationVariables>;
|
||||
|
||||
/**
|
||||
@ -4372,25 +4658,10 @@ export type UpdateOnePersonMutationOptions = Apollo.BaseMutationOptions<UpdateOn
|
||||
export const InsertOnePersonDocument = gql`
|
||||
mutation InsertOnePerson($data: PersonCreateInput!) {
|
||||
createOnePerson(data: $data) {
|
||||
id
|
||||
city
|
||||
company {
|
||||
domainName
|
||||
name
|
||||
id
|
||||
}
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
jobTitle
|
||||
linkedinUrl
|
||||
xUrl
|
||||
displayName
|
||||
phone
|
||||
createdAt
|
||||
...InsertPersonFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
${InsertPersonFragmentFragmentDoc}`;
|
||||
export type InsertOnePersonMutationFn = Apollo.MutationFunction<InsertOnePersonMutation, InsertOnePersonMutationVariables>;
|
||||
|
||||
/**
|
||||
@ -5346,6 +5617,72 @@ export function useCreateViewFieldsMutation(baseOptions?: Apollo.MutationHookOpt
|
||||
export type CreateViewFieldsMutationHookResult = ReturnType<typeof useCreateViewFieldsMutation>;
|
||||
export type CreateViewFieldsMutationResult = Apollo.MutationResult<CreateViewFieldsMutation>;
|
||||
export type CreateViewFieldsMutationOptions = Apollo.BaseMutationOptions<CreateViewFieldsMutation, CreateViewFieldsMutationVariables>;
|
||||
export const CreateViewSortsDocument = gql`
|
||||
mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) {
|
||||
createManyViewSort(data: $data) {
|
||||
count
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type CreateViewSortsMutationFn = Apollo.MutationFunction<CreateViewSortsMutation, CreateViewSortsMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useCreateViewSortsMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useCreateViewSortsMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useCreateViewSortsMutation` 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 [createViewSortsMutation, { data, loading, error }] = useCreateViewSortsMutation({
|
||||
* variables: {
|
||||
* data: // value for 'data'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useCreateViewSortsMutation(baseOptions?: Apollo.MutationHookOptions<CreateViewSortsMutation, CreateViewSortsMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<CreateViewSortsMutation, CreateViewSortsMutationVariables>(CreateViewSortsDocument, options);
|
||||
}
|
||||
export type CreateViewSortsMutationHookResult = ReturnType<typeof useCreateViewSortsMutation>;
|
||||
export type CreateViewSortsMutationResult = Apollo.MutationResult<CreateViewSortsMutation>;
|
||||
export type CreateViewSortsMutationOptions = Apollo.BaseMutationOptions<CreateViewSortsMutation, CreateViewSortsMutationVariables>;
|
||||
export const DeleteViewSortsDocument = gql`
|
||||
mutation DeleteViewSorts($where: ViewSortWhereInput!) {
|
||||
deleteManyViewSort(where: $where) {
|
||||
count
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type DeleteViewSortsMutationFn = Apollo.MutationFunction<DeleteViewSortsMutation, DeleteViewSortsMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useDeleteViewSortsMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useDeleteViewSortsMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useDeleteViewSortsMutation` 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 [deleteViewSortsMutation, { data, loading, error }] = useDeleteViewSortsMutation({
|
||||
* variables: {
|
||||
* where: // value for 'where'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useDeleteViewSortsMutation(baseOptions?: Apollo.MutationHookOptions<DeleteViewSortsMutation, DeleteViewSortsMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<DeleteViewSortsMutation, DeleteViewSortsMutationVariables>(DeleteViewSortsDocument, options);
|
||||
}
|
||||
export type DeleteViewSortsMutationHookResult = ReturnType<typeof useDeleteViewSortsMutation>;
|
||||
export type DeleteViewSortsMutationResult = Apollo.MutationResult<DeleteViewSortsMutation>;
|
||||
export type DeleteViewSortsMutationOptions = Apollo.BaseMutationOptions<DeleteViewSortsMutation, DeleteViewSortsMutationVariables>;
|
||||
export const GetViewFieldsDocument = gql`
|
||||
query GetViewFields($where: ViewFieldWhereInput, $orderBy: [ViewFieldOrderByWithRelationInput!]) {
|
||||
viewFields: findManyViewField(where: $where, orderBy: $orderBy) {
|
||||
@ -5386,6 +5723,43 @@ export function useGetViewFieldsLazyQuery(baseOptions?: Apollo.LazyQueryHookOpti
|
||||
export type GetViewFieldsQueryHookResult = ReturnType<typeof useGetViewFieldsQuery>;
|
||||
export type GetViewFieldsLazyQueryHookResult = ReturnType<typeof useGetViewFieldsLazyQuery>;
|
||||
export type GetViewFieldsQueryResult = Apollo.QueryResult<GetViewFieldsQuery, GetViewFieldsQueryVariables>;
|
||||
export const GetViewSortsDocument = gql`
|
||||
query GetViewSorts($where: ViewSortWhereInput) {
|
||||
viewSorts: findManyViewSort(where: $where) {
|
||||
direction
|
||||
key
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useGetViewSortsQuery__
|
||||
*
|
||||
* To run a query within a React component, call `useGetViewSortsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useGetViewSortsQuery` 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 } = useGetViewSortsQuery({
|
||||
* variables: {
|
||||
* where: // value for 'where'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useGetViewSortsQuery(baseOptions?: Apollo.QueryHookOptions<GetViewSortsQuery, GetViewSortsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useQuery<GetViewSortsQuery, GetViewSortsQueryVariables>(GetViewSortsDocument, options);
|
||||
}
|
||||
export function useGetViewSortsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetViewSortsQuery, GetViewSortsQueryVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useLazyQuery<GetViewSortsQuery, GetViewSortsQueryVariables>(GetViewSortsDocument, options);
|
||||
}
|
||||
export type GetViewSortsQueryHookResult = ReturnType<typeof useGetViewSortsQuery>;
|
||||
export type GetViewSortsLazyQueryHookResult = ReturnType<typeof useGetViewSortsLazyQuery>;
|
||||
export type GetViewSortsQueryResult = Apollo.QueryResult<GetViewSortsQuery, GetViewSortsQueryVariables>;
|
||||
export const UpdateViewFieldDocument = gql`
|
||||
mutation UpdateViewField($data: ViewFieldUpdateInput!, $where: ViewFieldWhereUniqueInput!) {
|
||||
updateOneViewField(data: $data, where: $where) {
|
||||
@ -5424,6 +5798,42 @@ export function useUpdateViewFieldMutation(baseOptions?: Apollo.MutationHookOpti
|
||||
export type UpdateViewFieldMutationHookResult = ReturnType<typeof useUpdateViewFieldMutation>;
|
||||
export type UpdateViewFieldMutationResult = Apollo.MutationResult<UpdateViewFieldMutation>;
|
||||
export type UpdateViewFieldMutationOptions = Apollo.BaseMutationOptions<UpdateViewFieldMutation, UpdateViewFieldMutationVariables>;
|
||||
export const UpdateViewSortDocument = gql`
|
||||
mutation UpdateViewSort($data: ViewSortUpdateInput!, $where: ViewSortWhereUniqueInput!) {
|
||||
viewSort: updateOneViewSort(data: $data, where: $where) {
|
||||
direction
|
||||
key
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
export type UpdateViewSortMutationFn = Apollo.MutationFunction<UpdateViewSortMutation, UpdateViewSortMutationVariables>;
|
||||
|
||||
/**
|
||||
* __useUpdateViewSortMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useUpdateViewSortMutation` within a React component and pass it any options that fit your needs.
|
||||
* When your component renders, `useUpdateViewSortMutation` 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 [updateViewSortMutation, { data, loading, error }] = useUpdateViewSortMutation({
|
||||
* variables: {
|
||||
* data: // value for 'data'
|
||||
* where: // value for 'where'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useUpdateViewSortMutation(baseOptions?: Apollo.MutationHookOptions<UpdateViewSortMutation, UpdateViewSortMutationVariables>) {
|
||||
const options = {...defaultOptions, ...baseOptions}
|
||||
return Apollo.useMutation<UpdateViewSortMutation, UpdateViewSortMutationVariables>(UpdateViewSortDocument, options);
|
||||
}
|
||||
export type UpdateViewSortMutationHookResult = ReturnType<typeof useUpdateViewSortMutation>;
|
||||
export type UpdateViewSortMutationResult = Apollo.MutationResult<UpdateViewSortMutation>;
|
||||
export type UpdateViewSortMutationOptions = Apollo.BaseMutationOptions<UpdateViewSortMutation, UpdateViewSortMutationVariables>;
|
||||
export const GetWorkspaceMembersDocument = gql`
|
||||
query GetWorkspaceMembers {
|
||||
workspaceMembers: findManyWorkspaceMember {
|
||||
|
@ -37,7 +37,7 @@ export function useOpenCreateActivityDrawer() {
|
||||
|
||||
return function openCreateActivityDrawer(
|
||||
type: ActivityType,
|
||||
entity?: CommentableEntity,
|
||||
entities?: CommentableEntity[],
|
||||
) {
|
||||
const now = new Date().toISOString();
|
||||
|
||||
@ -52,23 +52,19 @@ export function useOpenCreateActivityDrawer() {
|
||||
type: type,
|
||||
activityTargets: {
|
||||
createMany: {
|
||||
data: entity
|
||||
? [
|
||||
{
|
||||
commentableId: entity.id,
|
||||
commentableType: entity.type,
|
||||
companyId:
|
||||
entity.type === CommentableType.Company
|
||||
? entity.id
|
||||
: null,
|
||||
personId:
|
||||
entity.type === CommentableType.Person
|
||||
? entity.id
|
||||
: null,
|
||||
id: v4(),
|
||||
createdAt: now,
|
||||
},
|
||||
]
|
||||
data: entities
|
||||
? entities.map((entity) => ({
|
||||
commentableId: entity.id,
|
||||
commentableType: entity.type,
|
||||
companyId:
|
||||
entity.type === CommentableType.Company
|
||||
? entity.id
|
||||
: null,
|
||||
personId:
|
||||
entity.type === CommentableType.Person ? entity.id : null,
|
||||
id: v4(),
|
||||
createdAt: now,
|
||||
}))
|
||||
: [],
|
||||
skipDuplicates: true,
|
||||
},
|
||||
@ -85,7 +81,7 @@ export function useOpenCreateActivityDrawer() {
|
||||
onCompleted(data) {
|
||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||
setViewableActivityId(data.createOneActivity.id);
|
||||
setCommentableEntityArray(entity ? [entity] : []);
|
||||
setCommentableEntityArray(entities ?? []);
|
||||
openRightDrawer(RightDrawerPages.CreateActivity);
|
||||
},
|
||||
});
|
||||
|
@ -1,41 +1,19 @@
|
||||
import { getOperationName } from '@apollo/client/utilities/graphql/getFromAST';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { GET_COMPANIES } from '@/companies/queries';
|
||||
import { GET_PEOPLE } from '@/people/queries';
|
||||
import { useRightDrawer } from '@/ui/right-drawer/hooks/useRightDrawer';
|
||||
import { RightDrawerHotkeyScope } from '@/ui/right-drawer/types/RightDrawerHotkeyScope';
|
||||
import { RightDrawerPages } from '@/ui/right-drawer/types/RightDrawerPages';
|
||||
import { selectedRowIdsSelector } from '@/ui/table/states/selectedRowIdsSelector';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import {
|
||||
ActivityType,
|
||||
CommentableType,
|
||||
useCreateActivityMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { ActivityType, CommentableType } from '~/generated/graphql';
|
||||
|
||||
import { GET_ACTIVITIES_BY_TARGETS, GET_ACTIVITY } from '../queries';
|
||||
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
||||
import { viewableActivityIdState } from '../states/viewableActivityIdState';
|
||||
import { CommentableEntity } from '../types/CommentableEntity';
|
||||
|
||||
import { useOpenCreateActivityDrawer } from './useOpenCreateActivityDrawer';
|
||||
|
||||
export function useOpenCreateActivityDrawerForSelectedRowIds() {
|
||||
const { openRightDrawer } = useRightDrawer();
|
||||
const [createActivityMutation] = useCreateActivityMutation();
|
||||
const currentUser = useRecoilValue(currentUserState);
|
||||
const [, setViewableActivityId] = useRecoilState(viewableActivityIdState);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const [, setCommentableEntityArray] = useRecoilState(
|
||||
commentableEntityArrayState,
|
||||
);
|
||||
|
||||
const selectedEntityIds = useRecoilValue(selectedRowIdsSelector);
|
||||
|
||||
const openCreateActivityDrawer = useOpenCreateActivityDrawer();
|
||||
|
||||
return function openCreateCommentDrawerForSelectedRowIds(
|
||||
type: ActivityType,
|
||||
entityType: CommentableType,
|
||||
) {
|
||||
const commentableEntityArray: CommentableEntity[] = selectedEntityIds.map(
|
||||
@ -44,45 +22,6 @@ export function useOpenCreateActivityDrawerForSelectedRowIds() {
|
||||
id,
|
||||
}),
|
||||
);
|
||||
const now = new Date().toISOString();
|
||||
|
||||
createActivityMutation({
|
||||
variables: {
|
||||
data: {
|
||||
id: v4(),
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
author: { connect: { id: currentUser?.id ?? '' } },
|
||||
type: ActivityType.Note,
|
||||
activityTargets: {
|
||||
createMany: {
|
||||
data: commentableEntityArray.map((entity) => ({
|
||||
commentableId: entity.id,
|
||||
commentableType: entity.type,
|
||||
id: v4(),
|
||||
createdAt: new Date().toISOString(),
|
||||
companyId:
|
||||
entity.type === CommentableType.Company ? entity.id : null,
|
||||
personId:
|
||||
entity.type === CommentableType.Person ? entity.id : null,
|
||||
})),
|
||||
skipDuplicates: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
refetchQueries: [
|
||||
getOperationName(GET_COMPANIES) ?? '',
|
||||
getOperationName(GET_PEOPLE) ?? '',
|
||||
getOperationName(GET_ACTIVITY) ?? '',
|
||||
getOperationName(GET_ACTIVITIES_BY_TARGETS) ?? '',
|
||||
],
|
||||
onCompleted(data) {
|
||||
setHotkeyScope(RightDrawerHotkeyScope.RightDrawer, { goto: false });
|
||||
setViewableActivityId(data.createOneActivity.id);
|
||||
setCommentableEntityArray(commentableEntityArray);
|
||||
openRightDrawer(RightDrawerPages.CreateActivity);
|
||||
},
|
||||
});
|
||||
openCreateActivityDrawer(type, commentableEntityArray);
|
||||
};
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
|
||||
<StyledEmptyTimelineTitle>No activity yet</StyledEmptyTimelineTitle>
|
||||
<StyledEmptyTimelineSubTitle>Create one:</StyledEmptyTimelineSubTitle>
|
||||
<ActivityCreateButton
|
||||
onNoteClick={() => openCreateActivity(ActivityType.Note, entity)}
|
||||
onTaskClick={() => openCreateActivity(ActivityType.Task, entity)}
|
||||
onNoteClick={() => openCreateActivity(ActivityType.Note, [entity])}
|
||||
onTaskClick={() => openCreateActivity(ActivityType.Task, [entity])}
|
||||
/>
|
||||
</StyledTimelineEmptyContainer>
|
||||
);
|
||||
@ -132,8 +132,8 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
|
||||
<StyledMainContainer>
|
||||
<StyledTopActionBar>
|
||||
<ActivityCreateButton
|
||||
onNoteClick={() => openCreateActivity(ActivityType.Note, entity)}
|
||||
onTaskClick={() => openCreateActivity(ActivityType.Task, entity)}
|
||||
onNoteClick={() => openCreateActivity(ActivityType.Note, [entity])}
|
||||
onTaskClick={() => openCreateActivity(ActivityType.Task, [entity])}
|
||||
/>
|
||||
</StyledTopActionBar>
|
||||
<StyledTimelineContainer>
|
||||
|
@ -5,12 +5,11 @@ import { CompaniesSelectedSortType } from '../select';
|
||||
describe('reduceSortsToOrderBy', () => {
|
||||
it('should return an array of objects with the id as key and the order as value', () => {
|
||||
const sorts = [
|
||||
{ key: 'name', label: 'name', order: 'asc', _type: 'default_sort' },
|
||||
{ key: 'name', label: 'name', order: 'asc' },
|
||||
{
|
||||
key: 'domainName',
|
||||
label: 'domainName',
|
||||
order: 'desc',
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies CompaniesSelectedSortType[];
|
||||
const result = reduceSortsToOrderBy(sorts);
|
||||
|
@ -24,16 +24,20 @@ export const UPDATE_ONE_COMPANY = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
export const INSERT_COMPANY_FRAGMENT = gql`
|
||||
fragment InsertCompanyFragment on Company {
|
||||
domainName
|
||||
address
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
}
|
||||
`;
|
||||
|
||||
export const INSERT_ONE_COMPANY = gql`
|
||||
mutation InsertOneCompany($data: CompanyCreateInput!) {
|
||||
createOneCompany(data: $data) {
|
||||
address
|
||||
createdAt
|
||||
domainName
|
||||
linkedinUrl
|
||||
employees
|
||||
id
|
||||
name
|
||||
...InsertCompanyFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -1,30 +1,33 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { companyViewFields } from '@/companies/constants/companyViewFields';
|
||||
import { CompaniesSelectedSortType, defaultOrderBy } from '@/companies/queries';
|
||||
import { reduceSortsToOrderBy } from '@/ui/filter-n-sort/helpers';
|
||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||
import { sortsOrderByScopedState } from '@/ui/filter-n-sort/states/sortScopedState';
|
||||
import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
|
||||
import { IconList } from '@/ui/icon';
|
||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
||||
import { currentViewIdState } from '@/views/states/currentViewIdState';
|
||||
import {
|
||||
CompanyOrderByWithRelationInput,
|
||||
useGetCompaniesQuery,
|
||||
useUpdateOneCompanyMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { companiesFilters } from '~/pages/companies/companies-filters';
|
||||
import { availableSorts } from '~/pages/companies/companies-sorts';
|
||||
|
||||
export function CompanyTable() {
|
||||
const [orderBy, setOrderBy] =
|
||||
useState<CompanyOrderByWithRelationInput[]>(defaultOrderBy);
|
||||
import { defaultOrderBy } from '../../queries';
|
||||
|
||||
const updateSorts = useCallback((sorts: Array<CompaniesSelectedSortType>) => {
|
||||
setOrderBy(sorts.length ? reduceSortsToOrderBy(sorts) : defaultOrderBy);
|
||||
}, []);
|
||||
export function CompanyTable() {
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const orderBy = useRecoilScopedValue(sortsOrderByScopedState, TableContext);
|
||||
const { updateSorts } = useViewSorts({
|
||||
availableSorts,
|
||||
Context: TableContext,
|
||||
});
|
||||
|
||||
const filters = useRecoilScopedValue(filtersScopedState, TableContext);
|
||||
|
||||
@ -38,7 +41,7 @@ export function CompanyTable() {
|
||||
objectName="company"
|
||||
getRequestResultKey="companies"
|
||||
useGetRequest={useGetCompaniesQuery}
|
||||
orderBy={orderBy}
|
||||
orderBy={orderBy.length ? orderBy : defaultOrderBy}
|
||||
whereFilters={whereFilters}
|
||||
viewFieldDefinitions={companyViewFields}
|
||||
filterDefinitionArray={companiesFilters}
|
||||
@ -47,7 +50,7 @@ export function CompanyTable() {
|
||||
viewName="All Companies"
|
||||
viewIcon={<IconList size={16} />}
|
||||
availableSorts={availableSorts}
|
||||
onSortsUpdate={updateSorts}
|
||||
onSortsUpdate={currentViewId ? updateSorts : undefined}
|
||||
useUpdateEntityMutation={useUpdateOneCompanyMutation}
|
||||
/>
|
||||
</>
|
||||
|
@ -1,14 +1,24 @@
|
||||
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
||||
import { TableActionBarButtonToggleComments } from '@/ui/table/action-bar/components/TableActionBarButtonOpenComments';
|
||||
import { CommentableType } from '~/generated/graphql';
|
||||
import { TableActionBarButtonToggleTasks } from '@/ui/table/action-bar/components/TableActionBarButtonOpenTasks';
|
||||
import { ActivityType, CommentableType } from '~/generated/graphql';
|
||||
|
||||
export function TableActionBarButtonCreateActivityCompany() {
|
||||
const openCreateActivityRightDrawer =
|
||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||
|
||||
async function handleButtonClick() {
|
||||
openCreateActivityRightDrawer(CommentableType.Company);
|
||||
async function handleButtonClick(type: ActivityType) {
|
||||
openCreateActivityRightDrawer(type, CommentableType.Company);
|
||||
}
|
||||
|
||||
return <TableActionBarButtonToggleComments onClick={handleButtonClick} />;
|
||||
return (
|
||||
<>
|
||||
<TableActionBarButtonToggleComments
|
||||
onClick={() => handleButtonClick(ActivityType.Note)}
|
||||
/>
|
||||
<TableActionBarButtonToggleTasks
|
||||
onClick={() => handleButtonClick(ActivityType.Task)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { GET_COMPANIES } from '@/companies/queries';
|
||||
import { GET_PIPELINES } from '@/pipeline/queries';
|
||||
import { IconTrash } from '@/ui/icon/index';
|
||||
import { EntityTableActionBarButton } from '@/ui/table/action-bar/components/EntityTableActionBarButton';
|
||||
import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection';
|
||||
import { selectedRowIdsSelector } from '@/ui/table/states/selectedRowIdsSelector';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { useDeleteManyCompaniesMutation } from '~/generated/graphql';
|
||||
|
||||
export function TableActionBarButtonDeleteCompanies() {
|
||||
@ -15,12 +15,11 @@ export function TableActionBarButtonDeleteCompanies() {
|
||||
const resetRowSelection = useResetTableRowSelection();
|
||||
|
||||
const [deleteCompanies] = useDeleteManyCompaniesMutation({
|
||||
refetchQueries: [
|
||||
getOperationName(GET_COMPANIES) ?? '',
|
||||
getOperationName(GET_PIPELINES) ?? '',
|
||||
],
|
||||
refetchQueries: [getOperationName(GET_PIPELINES) ?? ''],
|
||||
});
|
||||
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
|
||||
async function handleDeleteClick() {
|
||||
const rowIdsToDelete = selectedRowIds;
|
||||
|
||||
@ -30,6 +29,17 @@ export function TableActionBarButtonDeleteCompanies() {
|
||||
variables: {
|
||||
ids: rowIdsToDelete,
|
||||
},
|
||||
optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
deleteManyCompany: {
|
||||
count: rowIdsToDelete.length,
|
||||
},
|
||||
},
|
||||
update: () => {
|
||||
setTableRowIds(
|
||||
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -26,25 +26,20 @@ export const UPDATE_ONE_PERSON = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
export const INSERT_PERSON_FRAGMENT = gql`
|
||||
fragment InsertPersonFragment on Person {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
displayName
|
||||
createdAt
|
||||
}
|
||||
`;
|
||||
|
||||
export const INSERT_ONE_PERSON = gql`
|
||||
mutation InsertOnePerson($data: PersonCreateInput!) {
|
||||
createOnePerson(data: $data) {
|
||||
id
|
||||
city
|
||||
company {
|
||||
domainName
|
||||
name
|
||||
id
|
||||
}
|
||||
email
|
||||
firstName
|
||||
lastName
|
||||
jobTitle
|
||||
linkedinUrl
|
||||
xUrl
|
||||
displayName
|
||||
phone
|
||||
createdAt
|
||||
...InsertPersonFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -1,31 +1,33 @@
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { defaultOrderBy } from '@/companies/queries';
|
||||
import { peopleViewFields } from '@/people/constants/peopleViewFields';
|
||||
import { PeopleSelectedSortType } from '@/people/queries';
|
||||
import { reduceSortsToOrderBy } from '@/ui/filter-n-sort/helpers';
|
||||
import { filtersScopedState } from '@/ui/filter-n-sort/states/filtersScopedState';
|
||||
import { sortsOrderByScopedState } from '@/ui/filter-n-sort/states/sortScopedState';
|
||||
import { turnFilterIntoWhereClause } from '@/ui/filter-n-sort/utils/turnFilterIntoWhereClause';
|
||||
import { IconList } from '@/ui/icon';
|
||||
import { EntityTable } from '@/ui/table/components/EntityTable';
|
||||
import { GenericEntityTableData } from '@/ui/table/components/GenericEntityTableData';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { useViewSorts } from '@/views/hooks/useViewSorts';
|
||||
import { currentViewIdState } from '@/views/states/currentViewIdState';
|
||||
import {
|
||||
PersonOrderByWithRelationInput,
|
||||
useGetPeopleQuery,
|
||||
useUpdateOnePersonMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { peopleFilters } from '~/pages/people/people-filters';
|
||||
import { availableSorts } from '~/pages/people/people-sorts';
|
||||
|
||||
export function PeopleTable() {
|
||||
const [orderBy, setOrderBy] =
|
||||
useState<PersonOrderByWithRelationInput[]>(defaultOrderBy);
|
||||
import { defaultOrderBy } from '../../queries';
|
||||
|
||||
const updateSorts = useCallback((sorts: Array<PeopleSelectedSortType>) => {
|
||||
setOrderBy(sorts.length ? reduceSortsToOrderBy(sorts) : defaultOrderBy);
|
||||
}, []);
|
||||
export function PeopleTable() {
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const orderBy = useRecoilScopedValue(sortsOrderByScopedState, TableContext);
|
||||
const { updateSorts } = useViewSorts({
|
||||
availableSorts,
|
||||
Context: TableContext,
|
||||
});
|
||||
|
||||
const filters = useRecoilScopedValue(filtersScopedState, TableContext);
|
||||
|
||||
@ -39,7 +41,7 @@ export function PeopleTable() {
|
||||
objectName="person"
|
||||
getRequestResultKey="people"
|
||||
useGetRequest={useGetPeopleQuery}
|
||||
orderBy={orderBy}
|
||||
orderBy={orderBy.length ? orderBy : defaultOrderBy}
|
||||
whereFilters={whereFilters}
|
||||
viewFieldDefinitions={peopleViewFields}
|
||||
filterDefinitionArray={peopleFilters}
|
||||
@ -48,7 +50,7 @@ export function PeopleTable() {
|
||||
viewName="All People"
|
||||
viewIcon={<IconList size={16} />}
|
||||
availableSorts={availableSorts}
|
||||
onSortsUpdate={updateSorts}
|
||||
onSortsUpdate={currentViewId ? updateSorts : undefined}
|
||||
useUpdateEntityMutation={useUpdateOnePersonMutation}
|
||||
/>
|
||||
</>
|
||||
|
@ -1,14 +1,24 @@
|
||||
import { useOpenCreateActivityDrawerForSelectedRowIds } from '@/activities/hooks/useOpenCreateActivityDrawerForSelectedRowIds';
|
||||
import { TableActionBarButtonToggleComments } from '@/ui/table/action-bar/components/TableActionBarButtonOpenComments';
|
||||
import { CommentableType } from '~/generated/graphql';
|
||||
import { TableActionBarButtonToggleTasks } from '@/ui/table/action-bar/components/TableActionBarButtonOpenTasks';
|
||||
import { ActivityType, CommentableType } from '~/generated/graphql';
|
||||
|
||||
export function TableActionBarButtonCreateActivityPeople() {
|
||||
const openCreateActivityRightDrawer =
|
||||
useOpenCreateActivityDrawerForSelectedRowIds();
|
||||
|
||||
async function handleButtonClick() {
|
||||
openCreateActivityRightDrawer(CommentableType.Person);
|
||||
async function handleButtonClick(type: ActivityType) {
|
||||
openCreateActivityRightDrawer(type, CommentableType.Person);
|
||||
}
|
||||
|
||||
return <TableActionBarButtonToggleComments onClick={handleButtonClick} />;
|
||||
return (
|
||||
<>
|
||||
<TableActionBarButtonToggleComments
|
||||
onClick={() => handleButtonClick(ActivityType.Note)}
|
||||
/>
|
||||
<TableActionBarButtonToggleTasks
|
||||
onClick={() => handleButtonClick(ActivityType.Task)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { GET_PEOPLE } from '@/people/queries';
|
||||
import { IconTrash } from '@/ui/icon/index';
|
||||
import { EntityTableActionBarButton } from '@/ui/table/action-bar/components/EntityTableActionBarButton';
|
||||
import { useResetTableRowSelection } from '@/ui/table/hooks/useResetTableRowSelection';
|
||||
import { selectedRowIdsSelector } from '@/ui/table/states/selectedRowIdsSelector';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { useDeleteManyPersonMutation } from '~/generated/graphql';
|
||||
|
||||
export function TableActionBarButtonDeletePeople() {
|
||||
const selectedRowIds = useRecoilValue(selectedRowIdsSelector);
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
|
||||
const resetRowSelection = useResetTableRowSelection();
|
||||
|
||||
@ -26,6 +28,17 @@ export function TableActionBarButtonDeletePeople() {
|
||||
variables: {
|
||||
ids: rowIdsToDelete,
|
||||
},
|
||||
optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
deleteManyPerson: {
|
||||
count: rowIdsToDelete.length,
|
||||
},
|
||||
},
|
||||
update: () => {
|
||||
setTableRowIds(
|
||||
tableRowIds.filter((id) => !rowIdsToDelete.includes(id)),
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2,27 +2,16 @@ import { SortOrder as Order_By } from '~/generated/graphql';
|
||||
|
||||
import { SelectedSortType } from './types/interface';
|
||||
|
||||
const mapOrderToOrder_By = (order: string) => {
|
||||
if (order === 'asc') return Order_By.Asc;
|
||||
return Order_By.Desc;
|
||||
};
|
||||
|
||||
export const defaultOrderByTemplateFactory =
|
||||
(key: string) => (order: string) => ({
|
||||
[key]: order,
|
||||
});
|
||||
|
||||
export const reduceSortsToOrderBy = <OrderByTemplate>(
|
||||
sorts: Array<SelectedSortType<OrderByTemplate>>,
|
||||
): OrderByTemplate[] => {
|
||||
const mappedSorts = sorts.map((sort) => {
|
||||
if (sort.orderByTemplates) {
|
||||
return sort.orderByTemplates?.map((orderByTemplate) =>
|
||||
orderByTemplate(mapOrderToOrder_By(sort.order)),
|
||||
sorts: SelectedSortType<OrderByTemplate>[],
|
||||
): OrderByTemplate[] =>
|
||||
sorts
|
||||
.map((sort) => {
|
||||
const order = sort.order === 'asc' ? Order_By.Asc : Order_By.Desc;
|
||||
return (
|
||||
sort.orderByTemplate?.(order) || [
|
||||
{ [sort.key]: order } as OrderByTemplate,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return defaultOrderByTemplateFactory(sort.key as string)(sort.order);
|
||||
});
|
||||
return mappedSorts.flat() as OrderByTemplate[];
|
||||
};
|
||||
})
|
||||
.flat();
|
||||
|
@ -1,8 +1,28 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
import { atomFamily, selectorFamily } from 'recoil';
|
||||
|
||||
import { Filter } from '../types/Filter';
|
||||
import { reduceSortsToOrderBy } from '../helpers';
|
||||
import { SelectedSortType } from '../types/interface';
|
||||
|
||||
export const sortScopedState = atomFamily<Filter[], string>({
|
||||
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))),
|
||||
});
|
||||
|
@ -6,7 +6,7 @@ export type SortType<OrderByTemplate> = {
|
||||
label: string;
|
||||
key: string;
|
||||
icon?: ReactNode;
|
||||
orderByTemplates?: Array<(order: Order_By) => OrderByTemplate>;
|
||||
orderByTemplate?: (order: Order_By) => OrderByTemplate[];
|
||||
};
|
||||
|
||||
export type SelectedSortType<OrderByTemplate> = SortType<OrderByTemplate> & {
|
||||
|
@ -0,0 +1,17 @@
|
||||
import { IconCheckbox } from '@/ui/icon/index';
|
||||
|
||||
import { EntityTableActionBarButton } from './EntityTableActionBarButton';
|
||||
|
||||
type OwnProps = {
|
||||
onClick: () => void;
|
||||
};
|
||||
|
||||
export function TableActionBarButtonToggleTasks({ onClick }: OwnProps) {
|
||||
return (
|
||||
<EntityTableActionBarButton
|
||||
label="Task"
|
||||
icon={<IconCheckbox size={16} />}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
}
|
@ -5,19 +5,20 @@ import styled from '@emotion/styled';
|
||||
import { useRecoilCallback, useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { IconButton } from '@/ui/button/components/IconButton';
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
} from '@/ui/editable-field/types/ViewField';
|
||||
import { IconPlus } from '@/ui/icon';
|
||||
import { useTrackPointer } from '@/ui/utilities/pointer-event/hooks/useTrackPointer';
|
||||
import { GET_VIEW_FIELDS } from '@/views/queries/select';
|
||||
import { currentViewIdState } from '@/views/states/currentViewIdState';
|
||||
import {
|
||||
useCreateViewFieldMutation,
|
||||
useUpdateViewFieldMutation,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
} from '../../editable-field/types/ViewField';
|
||||
import { toViewFieldInput } from '../hooks/useLoadView';
|
||||
import { toViewFieldInput } from '../hooks/useLoadViewFields';
|
||||
import { resizeFieldOffsetState } from '../states/resizeFieldOffsetState';
|
||||
import {
|
||||
addableViewFieldDefinitionsState,
|
||||
@ -89,6 +90,7 @@ export function EntityTableHeader() {
|
||||
const theme = useTheme();
|
||||
|
||||
const [{ objectName }, setViewFieldsState] = useRecoilState(viewFieldsState);
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const viewFields = useRecoilValue(visibleViewFieldsState);
|
||||
const columnWidths = useRecoilValue(columnWidthByViewFieldIdState);
|
||||
const addableViewFieldDefinitions = useRecoilValue(
|
||||
@ -176,15 +178,18 @@ export function EntityTableHeader() {
|
||||
|
||||
createViewFieldMutation({
|
||||
variables: {
|
||||
data: toViewFieldInput(objectName, {
|
||||
...viewFieldDefinition,
|
||||
columnOrder: viewFields.length + 1,
|
||||
}),
|
||||
data: {
|
||||
...toViewFieldInput(objectName, {
|
||||
...viewFieldDefinition,
|
||||
columnOrder: viewFields.length + 1,
|
||||
}),
|
||||
view: { connect: { id: currentViewId } },
|
||||
},
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''],
|
||||
});
|
||||
},
|
||||
[createViewFieldMutation, objectName, viewFields.length],
|
||||
[createViewFieldMutation, currentViewId, objectName, viewFields.length],
|
||||
);
|
||||
|
||||
return (
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
import { FilterDefinition } from '@/ui/filter-n-sort/types/FilterDefinition';
|
||||
import { useSetEntityTableData } from '@/ui/table/hooks/useSetEntityTableData';
|
||||
|
||||
import { useLoadView } from '../hooks/useLoadView';
|
||||
import { useLoadViewFields } from '../hooks/useLoadViewFields';
|
||||
|
||||
export function GenericEntityTableData({
|
||||
objectName,
|
||||
@ -27,7 +27,7 @@ export function GenericEntityTableData({
|
||||
}) {
|
||||
const setEntityTableData = useSetEntityTableData();
|
||||
|
||||
useLoadView({ objectName, viewFieldDefinitions });
|
||||
useLoadViewFields({ objectName, viewFieldDefinitions });
|
||||
|
||||
useGetRequest({
|
||||
variables: { orderBy, where: whereFilters },
|
||||
|
@ -40,7 +40,8 @@ export function GenericEditableDoubleTextChipCellDisplayMode({
|
||||
}),
|
||||
);
|
||||
|
||||
const displayName = `${firstValue} ${secondValue}`;
|
||||
const displayName =
|
||||
firstValue || secondValue ? `${firstValue} ${secondValue}` : ' ';
|
||||
|
||||
switch (viewField.metadata.entityType) {
|
||||
case Entity.Company: {
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
|
||||
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
|
||||
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
|
||||
import { isURL } from '~/utils/is-url';
|
||||
|
||||
import { TextCellEdit } from './TextCellEdit';
|
||||
|
||||
@ -30,6 +31,8 @@ export function GenericEditableURLCellEditMode({ viewField }: OwnProps) {
|
||||
function handleSubmit(newText: string) {
|
||||
if (newText === fieldValue) return;
|
||||
|
||||
if (!isURL(newText)) return;
|
||||
|
||||
setFieldValue(newText);
|
||||
|
||||
if (currentRowEntityId && updateField) {
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
ViewFieldTextMetadata,
|
||||
} from '@/ui/editable-field/types/ViewField';
|
||||
import { GET_VIEW_FIELDS } from '@/views/queries/select';
|
||||
import { currentViewIdState } from '@/views/states/currentViewIdState';
|
||||
import {
|
||||
SortOrder,
|
||||
useCreateViewFieldsMutation,
|
||||
useGetViewFieldsQuery,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import type {
|
||||
ViewFieldDefinition,
|
||||
ViewFieldMetadata,
|
||||
ViewFieldTextMetadata,
|
||||
} from '../../editable-field/types/ViewField';
|
||||
import { entityTableDimensionsState } from '../states/entityTableDimensionsState';
|
||||
import { viewFieldsState } from '../states/viewFieldsState';
|
||||
|
||||
@ -33,13 +34,14 @@ export const toViewFieldInput = (
|
||||
sizeInPx: viewFieldDefinition.columnSize,
|
||||
});
|
||||
|
||||
export const useLoadView = ({
|
||||
export const useLoadViewFields = ({
|
||||
objectName,
|
||||
viewFieldDefinitions,
|
||||
}: {
|
||||
objectName: 'company' | 'person';
|
||||
viewFieldDefinitions: ViewFieldDefinition<ViewFieldMetadata>[];
|
||||
}) => {
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const setEntityTableDimensions = useSetRecoilState(
|
||||
entityTableDimensionsState,
|
||||
);
|
||||
@ -50,7 +52,10 @@ export const useLoadView = ({
|
||||
useGetViewFieldsQuery({
|
||||
variables: {
|
||||
orderBy: { index: SortOrder.Asc },
|
||||
where: { objectName: { equals: objectName } },
|
||||
where: {
|
||||
objectName: { equals: objectName },
|
||||
viewId: { equals: currentViewId ?? null },
|
||||
},
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
if (data.viewFields.length) {
|
||||
@ -79,9 +84,10 @@ export const useLoadView = ({
|
||||
// Populate if empty
|
||||
createViewFieldsMutation({
|
||||
variables: {
|
||||
data: viewFieldDefinitions.map((viewFieldDefinition) =>
|
||||
toViewFieldInput(objectName, viewFieldDefinition),
|
||||
),
|
||||
data: viewFieldDefinitions.map((viewFieldDefinition) => ({
|
||||
...toViewFieldInput(objectName, viewFieldDefinition),
|
||||
viewId: currentViewId,
|
||||
})),
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEW_FIELDS) ?? ''],
|
||||
});
|
@ -1,12 +1,14 @@
|
||||
import { ReactNode, useCallback, useState } from 'react';
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { FilterDropdownButton } from '@/ui/filter-n-sort/components/FilterDropdownButton';
|
||||
import SortAndFilterBar from '@/ui/filter-n-sort/components/SortAndFilterBar';
|
||||
import { SortDropdownButton } from '@/ui/filter-n-sort/components/SortDropdownButton';
|
||||
import { sortScopedState } from '@/ui/filter-n-sort/states/sortScopedState';
|
||||
import { FiltersHotkeyScope } from '@/ui/filter-n-sort/types/FiltersHotkeyScope';
|
||||
import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { TopBar } from '@/ui/top-bar/TopBar';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { OptionsDropdownButton } from '@/views/components/OptionsDropdownButton';
|
||||
|
||||
import { TableContext } from '../../states/TableContext';
|
||||
@ -34,26 +36,26 @@ export function TableHeader<SortField>({
|
||||
availableSorts,
|
||||
onSortsUpdate,
|
||||
}: OwnProps<SortField>) {
|
||||
const [sorts, innerSetSorts] = useState<Array<SelectedSortType<SortField>>>(
|
||||
[],
|
||||
const [sorts, setSorts] = useRecoilScopedState<SelectedSortType<SortField>[]>(
|
||||
sortScopedState,
|
||||
TableContext,
|
||||
);
|
||||
const handleSortsUpdate = onSortsUpdate ?? setSorts;
|
||||
|
||||
const sortSelect = useCallback(
|
||||
(newSort: SelectedSortType<SortField>) => {
|
||||
const newSorts = updateSortOrFilterByKey(sorts, newSort);
|
||||
innerSetSorts(newSorts);
|
||||
onSortsUpdate && onSortsUpdate(newSorts);
|
||||
handleSortsUpdate(newSorts);
|
||||
},
|
||||
[onSortsUpdate, sorts],
|
||||
[handleSortsUpdate, sorts],
|
||||
);
|
||||
|
||||
const sortUnselect = useCallback(
|
||||
(sortKey: string) => {
|
||||
const newSorts = sorts.filter((sort) => sort.key !== sortKey);
|
||||
innerSetSorts(newSorts);
|
||||
onSortsUpdate && onSortsUpdate(newSorts);
|
||||
handleSortsUpdate(newSorts);
|
||||
},
|
||||
[onSortsUpdate, sorts],
|
||||
[handleSortsUpdate, sorts],
|
||||
);
|
||||
|
||||
return (
|
||||
@ -88,8 +90,7 @@ export function TableHeader<SortField>({
|
||||
sorts={sorts}
|
||||
onRemoveSort={sortUnselect}
|
||||
onCancelClick={() => {
|
||||
innerSetSorts([]);
|
||||
onSortsUpdate && onSortsUpdate([]);
|
||||
handleSortsUpdate([]);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Context, useContext } from 'react';
|
||||
import { RecoilState, useRecoilValue } from 'recoil';
|
||||
import { RecoilState, RecoilValueReadOnly, useRecoilValue } from 'recoil';
|
||||
|
||||
import { RecoilScopeContext } from '../states/RecoilScopeContext';
|
||||
|
||||
export function useRecoilScopedValue<T>(
|
||||
recoilState: (param: string) => RecoilState<T>,
|
||||
recoilState: (param: string) => RecoilState<T> | RecoilValueReadOnly<T>,
|
||||
SpecificContext?: Context<string | null>,
|
||||
) {
|
||||
const recoilScopeId = useContext(SpecificContext ?? RecoilScopeContext);
|
||||
|
152
front/src/modules/views/hooks/useViewSorts.ts
Normal file
152
front/src/modules/views/hooks/useViewSorts.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import { Context, useCallback } from 'react';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import {
|
||||
sortsByKeyScopedState,
|
||||
sortScopedState,
|
||||
} from '@/ui/filter-n-sort/states/sortScopedState';
|
||||
import type {
|
||||
SelectedSortType,
|
||||
SortType,
|
||||
} from '@/ui/filter-n-sort/types/interface';
|
||||
import { useRecoilScopedState } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedState';
|
||||
import { useRecoilScopedValue } from '@/ui/utilities/recoil-scope/hooks/useRecoilScopedValue';
|
||||
import { currentViewIdState } from '@/views/states/currentViewIdState';
|
||||
import {
|
||||
useCreateViewSortsMutation,
|
||||
useDeleteViewSortsMutation,
|
||||
useGetViewSortsQuery,
|
||||
useUpdateViewSortMutation,
|
||||
ViewSortDirection,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import { GET_VIEW_SORTS } from '../queries/select';
|
||||
|
||||
export const useViewSorts = <SortField>({
|
||||
availableSorts,
|
||||
Context,
|
||||
}: {
|
||||
availableSorts: SortType<SortField>[];
|
||||
Context?: Context<string | null>;
|
||||
}) => {
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const [, setSorts] = useRecoilScopedState(sortScopedState, Context);
|
||||
const sortsByKey = useRecoilScopedValue(sortsByKeyScopedState, Context);
|
||||
|
||||
useGetViewSortsQuery({
|
||||
skip: !currentViewId,
|
||||
variables: {
|
||||
where: {
|
||||
viewId: { equals: currentViewId },
|
||||
},
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setSorts(
|
||||
data.viewSorts
|
||||
.map((viewSort) => ({
|
||||
...availableSorts.find((sort) => sort.key === viewSort.key),
|
||||
label: viewSort.name,
|
||||
order: viewSort.direction.toLowerCase(),
|
||||
}))
|
||||
.filter((sort): sort is SelectedSortType<SortField> => !!sort),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const [createViewSortsMutation] = useCreateViewSortsMutation();
|
||||
const [updateViewSortMutation] = useUpdateViewSortMutation();
|
||||
const [deleteViewSortsMutation] = useDeleteViewSortsMutation();
|
||||
|
||||
const createViewSorts = useCallback(
|
||||
(sorts: SelectedSortType<SortField>[]) => {
|
||||
if (!currentViewId || !sorts.length) return;
|
||||
|
||||
return createViewSortsMutation({
|
||||
variables: {
|
||||
data: sorts.map((sort) => ({
|
||||
key: sort.key,
|
||||
direction: sort.order as ViewSortDirection,
|
||||
name: sort.label,
|
||||
viewId: currentViewId,
|
||||
})),
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
||||
});
|
||||
},
|
||||
[createViewSortsMutation, currentViewId],
|
||||
);
|
||||
|
||||
const updateViewSorts = useCallback(
|
||||
(sorts: SelectedSortType<SortField>[]) => {
|
||||
if (!currentViewId || !sorts.length) return;
|
||||
|
||||
return Promise.all(
|
||||
sorts.map((sort) =>
|
||||
updateViewSortMutation({
|
||||
variables: {
|
||||
data: {
|
||||
direction: sort.order as ViewSortDirection,
|
||||
},
|
||||
where: {
|
||||
viewId_key: { key: sort.key, viewId: currentViewId },
|
||||
},
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
[currentViewId, updateViewSortMutation],
|
||||
);
|
||||
|
||||
const deleteViewSorts = useCallback(
|
||||
(sortKeys: string[]) => {
|
||||
if (!currentViewId || !sortKeys.length) return;
|
||||
|
||||
return deleteViewSortsMutation({
|
||||
variables: {
|
||||
where: {
|
||||
key: { in: sortKeys },
|
||||
viewId: { equals: currentViewId },
|
||||
},
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_VIEW_SORTS) ?? ''],
|
||||
});
|
||||
},
|
||||
[currentViewId, deleteViewSortsMutation],
|
||||
);
|
||||
|
||||
const updateSorts = useCallback(
|
||||
async (nextSorts: SelectedSortType<SortField>[]) => {
|
||||
if (!currentViewId) return;
|
||||
|
||||
const sortsToCreate = nextSorts.filter(
|
||||
(nextSort) => !sortsByKey[nextSort.key],
|
||||
);
|
||||
await createViewSorts(sortsToCreate);
|
||||
|
||||
const sortsToUpdate = nextSorts.filter(
|
||||
(nextSort) =>
|
||||
sortsByKey[nextSort.key] &&
|
||||
sortsByKey[nextSort.key].order !== nextSort.order,
|
||||
);
|
||||
await updateViewSorts(sortsToUpdate);
|
||||
|
||||
const nextSortKeys = nextSorts.map((nextSort) => nextSort.key);
|
||||
const sortKeysToDelete = Object.keys(sortsByKey).filter(
|
||||
(previousSortKey) => !nextSortKeys.includes(previousSortKey),
|
||||
);
|
||||
return deleteViewSorts(sortKeysToDelete);
|
||||
},
|
||||
[
|
||||
createViewSorts,
|
||||
currentViewId,
|
||||
deleteViewSorts,
|
||||
sortsByKey,
|
||||
updateViewSorts,
|
||||
],
|
||||
);
|
||||
|
||||
return { updateSorts };
|
||||
};
|
@ -19,3 +19,11 @@ export const CREATE_VIEW_FIELDS = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const CREATE_VIEW_SORTS = gql`
|
||||
mutation CreateViewSorts($data: [ViewSortCreateManyInput!]!) {
|
||||
createManyViewSort(data: $data) {
|
||||
count
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
9
front/src/modules/views/queries/delete.ts
Normal file
9
front/src/modules/views/queries/delete.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const DELETE_VIEW_SORTS = gql`
|
||||
mutation DeleteViewSorts($where: ViewSortWhereInput!) {
|
||||
deleteManyViewSort(where: $where) {
|
||||
count
|
||||
}
|
||||
}
|
||||
`;
|
@ -14,3 +14,13 @@ export const GET_VIEW_FIELDS = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_VIEW_SORTS = gql`
|
||||
query GetViewSorts($where: ViewSortWhereInput) {
|
||||
viewSorts: findManyViewSort(where: $where) {
|
||||
direction
|
||||
key
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -14,3 +14,16 @@ export const UPDATE_VIEW_FIELD = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_VIEW_SORT = gql`
|
||||
mutation UpdateViewSort(
|
||||
$data: ViewSortUpdateInput!
|
||||
$where: ViewSortWhereUniqueInput!
|
||||
) {
|
||||
viewSort: updateOneViewSort(data: $data, where: $where) {
|
||||
direction
|
||||
key
|
||||
name
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
6
front/src/modules/views/states/currentViewIdState.ts
Normal file
6
front/src/modules/views/states/currentViewIdState.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const currentViewIdState = atom<string | undefined>({
|
||||
key: 'currentViewIdState',
|
||||
default: undefined,
|
||||
});
|
@ -1,20 +1,21 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { GET_COMPANIES } from '@/companies/queries';
|
||||
import { CompanyTable } from '@/companies/table/components/CompanyTable';
|
||||
import { TableActionBarButtonCreateActivityCompany } from '@/companies/table/components/TableActionBarButtonCreateActivityCompany';
|
||||
import { TableActionBarButtonDeleteCompanies } from '@/companies/table/components/TableActionBarButtonDeleteCompanies';
|
||||
import { SEARCH_COMPANY_QUERY } from '@/search/queries/search';
|
||||
import { IconBuildingSkyscraper } from '@/ui/icon';
|
||||
import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer';
|
||||
import { EntityTableActionBar } from '@/ui/table/action-bar/components/EntityTableActionBar';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { useInsertOneCompanyMutation } from '~/generated/graphql';
|
||||
|
||||
import { SEARCH_COMPANY_QUERY } from '../../modules/search/queries/search';
|
||||
|
||||
const StyledTableContainer = styled.div`
|
||||
display: flex;
|
||||
width: 100%;
|
||||
@ -22,20 +23,35 @@ const StyledTableContainer = styled.div`
|
||||
|
||||
export function Companies() {
|
||||
const [insertCompany] = useInsertOneCompanyMutation();
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
const newCompanyId: string = v4();
|
||||
await insertCompany({
|
||||
variables: {
|
||||
data: {
|
||||
id: newCompanyId,
|
||||
name: '',
|
||||
domainName: '',
|
||||
address: '',
|
||||
},
|
||||
},
|
||||
refetchQueries: [
|
||||
getOperationName(GET_COMPANIES) ?? '',
|
||||
getOperationName(SEARCH_COMPANY_QUERY) ?? '',
|
||||
],
|
||||
optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
createOneCompany: {
|
||||
__typename: 'Company',
|
||||
id: newCompanyId,
|
||||
name: '',
|
||||
domainName: '',
|
||||
address: '',
|
||||
createdAt: '',
|
||||
},
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
data?.createOneCompany.id &&
|
||||
setTableRowIds([data?.createOneCompany.id, ...tableRowIds]);
|
||||
},
|
||||
refetchQueries: [getOperationName(SEARCH_COMPANY_QUERY) ?? ''],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
} from '@/ui/icon/index';
|
||||
import { CompanyOrderByWithRelationInput as Companies_Order_By } from '~/generated/graphql';
|
||||
|
||||
export const availableSorts = [
|
||||
export const availableSorts: SortType<Companies_Order_By>[] = [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
@ -34,4 +34,4 @@ export const availableSorts = [
|
||||
label: 'Creation',
|
||||
icon: <IconCalendarEvent size={16} />,
|
||||
},
|
||||
] satisfies Array<SortType<Companies_Order_By>>;
|
||||
];
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { GET_PEOPLE } from '@/people/queries';
|
||||
import { PeopleTable } from '@/people/table/components/PeopleTable';
|
||||
import { TableActionBarButtonCreateActivityPeople } from '@/people/table/components/TableActionBarButtonCreateActivityPeople';
|
||||
import { TableActionBarButtonDeletePeople } from '@/people/table/components/TableActionBarButtonDeletePeople';
|
||||
@ -10,6 +10,7 @@ import { IconUser } from '@/ui/icon';
|
||||
import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer';
|
||||
import { EntityTableActionBar } from '@/ui/table/action-bar/components/EntityTableActionBar';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { useInsertOnePersonMutation } from '~/generated/graphql';
|
||||
|
||||
@ -20,16 +21,33 @@ const StyledTableContainer = styled.div`
|
||||
|
||||
export function People() {
|
||||
const [insertOnePerson] = useInsertOnePersonMutation();
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
const newPersonId: string = v4();
|
||||
await insertOnePerson({
|
||||
variables: {
|
||||
data: {
|
||||
id: newPersonId,
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
},
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_PEOPLE) ?? ''],
|
||||
optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
createOnePerson: {
|
||||
__typename: 'Person',
|
||||
id: newPersonId,
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
displayName: '',
|
||||
createdAt: '',
|
||||
},
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
data?.createOnePerson?.id &&
|
||||
setTableRowIds([data?.createOnePerson.id, ...tableRowIds]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,19 +12,15 @@ import {
|
||||
SortOrder as Order_By,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
export const availableSorts = [
|
||||
export const availableSorts: SortType<People_Order_By>[] = [
|
||||
{
|
||||
key: 'fullname',
|
||||
label: 'People',
|
||||
icon: <IconUser size={16} />,
|
||||
|
||||
orderByTemplates: [
|
||||
(order: Order_By) => ({
|
||||
firstName: order,
|
||||
}),
|
||||
(order: Order_By) => ({
|
||||
lastName: order,
|
||||
}),
|
||||
orderByTemplate: (order: Order_By) => [
|
||||
{ firstName: order },
|
||||
{ lastName: order },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -32,7 +28,7 @@ export const availableSorts = [
|
||||
label: 'Company',
|
||||
icon: <IconBuildingSkyscraper size={16} />,
|
||||
|
||||
orderByTemplates: [(order: Order_By) => ({ company: { name: order } })],
|
||||
orderByTemplate: (order: Order_By) => [{ company: { name: order } }],
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
@ -54,4 +50,4 @@ export const availableSorts = [
|
||||
label: 'City',
|
||||
icon: <IconMap size={16} />,
|
||||
},
|
||||
] satisfies Array<SortType<People_Order_By>>;
|
||||
];
|
||||
|
@ -186,14 +186,22 @@ export function AuthAutoRouter() {
|
||||
label: 'Create Task',
|
||||
type: CommandType.Create,
|
||||
icon: <IconCheckbox />,
|
||||
onCommandClick: () => openCreateActivity(ActivityType.Task, entity),
|
||||
onCommandClick: () =>
|
||||
openCreateActivity(
|
||||
ActivityType.Task,
|
||||
entity ? [entity] : undefined,
|
||||
),
|
||||
},
|
||||
{
|
||||
to: '',
|
||||
label: 'Create Note',
|
||||
type: CommandType.Create,
|
||||
icon: <IconNotes />,
|
||||
onCommandClick: () => openCreateActivity(ActivityType.Note, entity),
|
||||
onCommandClick: () =>
|
||||
openCreateActivity(
|
||||
ActivityType.Note,
|
||||
entity ? [entity] : undefined,
|
||||
),
|
||||
},
|
||||
]);
|
||||
break;
|
||||
@ -212,14 +220,22 @@ export function AuthAutoRouter() {
|
||||
label: 'Create Task',
|
||||
type: CommandType.Create,
|
||||
icon: <IconCheckbox />,
|
||||
onCommandClick: () => openCreateActivity(ActivityType.Task, entity),
|
||||
onCommandClick: () =>
|
||||
openCreateActivity(
|
||||
ActivityType.Task,
|
||||
entity ? [entity] : undefined,
|
||||
),
|
||||
},
|
||||
{
|
||||
to: '',
|
||||
label: 'Create Note',
|
||||
type: CommandType.Create,
|
||||
icon: <IconNotes />,
|
||||
onCommandClick: () => openCreateActivity(ActivityType.Note, entity),
|
||||
onCommandClick: () =>
|
||||
openCreateActivity(
|
||||
ActivityType.Note,
|
||||
entity ? [entity] : undefined,
|
||||
),
|
||||
},
|
||||
]);
|
||||
break;
|
||||
|
35
front/src/utils/__tests__/is-url.test.ts
Normal file
35
front/src/utils/__tests__/is-url.test.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { isURL } from '~/utils/is-url';
|
||||
|
||||
describe('isURL', () => {
|
||||
it(`should return false if null`, () => {
|
||||
expect(isURL(null)).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return false if undefined`, () => {
|
||||
expect(isURL(undefined)).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string google`, () => {
|
||||
expect(isURL('google')).toBeFalsy();
|
||||
});
|
||||
|
||||
it(`should return true if string google.com`, () => {
|
||||
expect(isURL('google.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string bbc.co.uk`, () => {
|
||||
expect(isURL('bbc.co.uk')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string web.io`, () => {
|
||||
expect(isURL('web.io')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string x.com`, () => {
|
||||
expect(isURL('x.com')).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should return true if string 2.com`, () => {
|
||||
expect(isURL('2.com')).toBeTruthy();
|
||||
});
|
||||
});
|
10
front/src/utils/is-url.ts
Normal file
10
front/src/utils/is-url.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { isDefined } from './isDefined';
|
||||
|
||||
export function isURL(url: string | undefined | null) {
|
||||
return (
|
||||
isDefined(url) &&
|
||||
/^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$/.test(
|
||||
url,
|
||||
)
|
||||
);
|
||||
}
|
@ -17,7 +17,9 @@ import {
|
||||
PipelineStage,
|
||||
PipelineProgress,
|
||||
UserSettings,
|
||||
View,
|
||||
ViewField,
|
||||
ViewSort,
|
||||
} from '@prisma/client';
|
||||
|
||||
import { AbilityAction } from './ability.action';
|
||||
@ -37,7 +39,9 @@ type SubjectsAbility = Subjects<{
|
||||
PipelineProgress: PipelineProgress;
|
||||
Attachment: Attachment;
|
||||
UserSettings: UserSettings;
|
||||
View: View;
|
||||
ViewField: ViewField;
|
||||
ViewSort: ViewSort;
|
||||
}>;
|
||||
|
||||
export type AppAbility = PureAbility<
|
||||
@ -130,11 +134,22 @@ export class AbilityFactory {
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
// View
|
||||
can(AbilityAction.Read, 'View', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Create, 'View', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Update, 'View', { workspaceId: workspace.id });
|
||||
|
||||
// ViewField
|
||||
can(AbilityAction.Read, 'ViewField', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Create, 'ViewField', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Update, 'ViewField', { workspaceId: workspace.id });
|
||||
|
||||
// ViewSort
|
||||
can(AbilityAction.Read, 'ViewSort', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Create, 'ViewSort', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Update, 'ViewSort', { workspaceId: workspace.id });
|
||||
can(AbilityAction.Delete, 'ViewSort', { workspaceId: workspace.id });
|
||||
|
||||
return build();
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,12 @@ import {
|
||||
ReadViewFieldAbilityHandler,
|
||||
UpdateViewFieldAbilityHandler,
|
||||
} from './handlers/view-field.ability-handler';
|
||||
import {
|
||||
CreateViewSortAbilityHandler,
|
||||
ReadViewSortAbilityHandler,
|
||||
UpdateViewSortAbilityHandler,
|
||||
DeleteViewSortAbilityHandler,
|
||||
} from './handlers/view-sort.ability-handler';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
@ -187,6 +193,11 @@ import {
|
||||
ReadViewFieldAbilityHandler,
|
||||
CreateViewFieldAbilityHandler,
|
||||
UpdateViewFieldAbilityHandler,
|
||||
// ViewSort
|
||||
ReadViewSortAbilityHandler,
|
||||
CreateViewSortAbilityHandler,
|
||||
UpdateViewSortAbilityHandler,
|
||||
DeleteViewSortAbilityHandler,
|
||||
],
|
||||
exports: [
|
||||
AbilityFactory,
|
||||
@ -272,6 +283,11 @@ import {
|
||||
ReadViewFieldAbilityHandler,
|
||||
CreateViewFieldAbilityHandler,
|
||||
UpdateViewFieldAbilityHandler,
|
||||
// ViewSort
|
||||
ReadViewSortAbilityHandler,
|
||||
CreateViewSortAbilityHandler,
|
||||
UpdateViewSortAbilityHandler,
|
||||
DeleteViewSortAbilityHandler,
|
||||
],
|
||||
})
|
||||
export class AbilityModule {}
|
||||
|
122
server/src/ability/handlers/view-sort.ability-handler.ts
Normal file
122
server/src/ability/handlers/view-sort.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 { ViewSortWhereUniqueInput } from 'src/core/@generated/view-sort/view-sort-where-unique.input';
|
||||
import { ViewSortWhereInput } from 'src/core/@generated/view-sort/view-sort-where.input';
|
||||
|
||||
class ViewSortArgs {
|
||||
where?: ViewSortWhereInput | ViewSortWhereUniqueInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const isViewSortWhereUniqueInput = (
|
||||
input: ViewSortWhereInput | ViewSortWhereUniqueInput,
|
||||
): input is ViewSortWhereUniqueInput => 'viewId_key' in input;
|
||||
|
||||
@Injectable()
|
||||
export class ReadViewSortAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
return ability.can(AbilityAction.Read, 'ViewSort');
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewSortAbilityHandler 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(
|
||||
'ViewSort',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'ViewSort');
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewSortAbilityHandler implements IAbilityHandler {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<ViewSortArgs>();
|
||||
const viewSort = await this.prismaService.client.viewSort.findFirst({
|
||||
where:
|
||||
args.where && isViewSortWhereUniqueInput(args.where)
|
||||
? args.where.viewId_key
|
||||
: args.where,
|
||||
});
|
||||
assert(viewSort, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'ViewSort',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('ViewSort', viewSort));
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewSortAbilityHandler implements IAbilityHandler {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<ViewSortArgs>();
|
||||
const where = convertToWhereInput(
|
||||
args.where && isViewSortWhereUniqueInput(args.where)
|
||||
? args.where.viewId_key
|
||||
: args.where,
|
||||
);
|
||||
const viewSorts = await this.prismaService.client.viewSort.findMany({
|
||||
where,
|
||||
});
|
||||
assert(viewSorts.length, '', NotFoundException);
|
||||
|
||||
for (const viewSort of viewSorts) {
|
||||
const allowed = ability.can(
|
||||
AbilityAction.Delete,
|
||||
subject('ViewSort', viewSort),
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
79
server/src/ability/handlers/view.ability-handler.ts
Normal file
79
server/src/ability/handlers/view.ability-handler.ts
Normal file
@ -0,0 +1,79 @@
|
||||
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 { relationAbilityChecker } from 'src/ability/ability.util';
|
||||
import { ViewWhereInput } from 'src/core/@generated/view/view-where.input';
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { assert } from 'src/utils/assert';
|
||||
|
||||
class ViewArgs {
|
||||
where?: ViewWhereInput;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class ReadViewAbilityHandler implements IAbilityHandler {
|
||||
handle(ability: AppAbility) {
|
||||
return ability.can(AbilityAction.Read, 'View');
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewAbilityHandler 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(
|
||||
'View',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Create, 'View');
|
||||
}
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewAbilityHandler implements IAbilityHandler {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async handle(ability: AppAbility, context: ExecutionContext) {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const args = gqlContext.getArgs<ViewArgs>();
|
||||
const view = await this.prismaService.client.view.findFirst({
|
||||
where: args.where,
|
||||
});
|
||||
assert(view, '', NotFoundException);
|
||||
|
||||
const allowed = await relationAbilityChecker(
|
||||
'View',
|
||||
ability,
|
||||
this.prismaService.client,
|
||||
args,
|
||||
);
|
||||
|
||||
if (!allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ability.can(AbilityAction.Update, subject('View', view));
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ export class ViewFieldResolver {
|
||||
): Promise<Partial<ViewField>> {
|
||||
return this.viewFieldService.create({
|
||||
data: {
|
||||
...args.data,
|
||||
...(args.data as Prisma.ViewFieldCreateInput),
|
||||
workspace: { connect: { id: workspace.id } },
|
||||
},
|
||||
select: prismaSelect.value,
|
||||
|
32
server/src/core/view/resolvers/view-sort.resolver.spec.ts
Normal file
32
server/src/core/view/resolvers/view-sort.resolver.spec.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { ViewSortService } from 'src/core/view/services/view-sort.service';
|
||||
import { AbilityFactory } from 'src/ability/ability.factory';
|
||||
|
||||
import { ViewSortResolver } from './view-sort.resolver';
|
||||
|
||||
describe('ViewSortResolver', () => {
|
||||
let resolver: ViewSortResolver;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
ViewSortResolver,
|
||||
{
|
||||
provide: ViewSortService,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: AbilityFactory,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
resolver = module.get<ViewSortResolver>(ViewSortResolver);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(resolver).toBeDefined();
|
||||
});
|
||||
});
|
102
server/src/core/view/resolvers/view-sort.resolver.ts
Normal file
102
server/src/core/view/resolvers/view-sort.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 {
|
||||
CreateViewSortAbilityHandler,
|
||||
DeleteViewSortAbilityHandler,
|
||||
ReadViewSortAbilityHandler,
|
||||
UpdateViewSortAbilityHandler,
|
||||
} from 'src/ability/handlers/view-sort.ability-handler';
|
||||
import { FindManyViewSortArgs } from 'src/core/@generated/view-sort/find-many-view-sort.args';
|
||||
import { ViewSort } from 'src/core/@generated/view-sort/view-sort.model';
|
||||
import { ViewSortService } from 'src/core/view/services/view-sort.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 { UpdateOneViewSortArgs } from 'src/core/@generated/view-sort/update-one-view-sort.args';
|
||||
import { AuthWorkspace } from 'src/decorators/auth-workspace.decorator';
|
||||
import { AffectedRows } from 'src/core/@generated/prisma/affected-rows.output';
|
||||
import { DeleteManyViewSortArgs } from 'src/core/@generated/view-sort/delete-many-view-sort.args';
|
||||
import { CreateManyViewSortArgs } from 'src/core/@generated/view-sort/create-many-view-sort.args';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Resolver(() => ViewSort)
|
||||
export class ViewSortResolver {
|
||||
constructor(private readonly viewSortService: ViewSortService) {}
|
||||
|
||||
@Mutation(() => AffectedRows)
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(CreateViewSortAbilityHandler)
|
||||
async createManyViewSort(
|
||||
@Args() args: CreateManyViewSortArgs,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
): Promise<AffectedRows> {
|
||||
return this.viewSortService.createMany({
|
||||
data: args.data.map((data) => ({
|
||||
...data,
|
||||
workspaceId: workspace.id,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => [ViewSort])
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(ReadViewSortAbilityHandler)
|
||||
async findManyViewSort(
|
||||
@Args() args: FindManyViewSortArgs,
|
||||
@UserAbility() ability: AppAbility,
|
||||
@PrismaSelector({ modelName: 'ViewSort' })
|
||||
prismaSelect: PrismaSelect<'ViewSort'>,
|
||||
): Promise<Partial<ViewSort>[]> {
|
||||
return this.viewSortService.findMany({
|
||||
where: args.where
|
||||
? {
|
||||
AND: [args.where, accessibleBy(ability).ViewSort],
|
||||
}
|
||||
: accessibleBy(ability).ViewSort,
|
||||
orderBy: args.orderBy,
|
||||
cursor: args.cursor,
|
||||
take: args.take,
|
||||
skip: args.skip,
|
||||
distinct: args.distinct,
|
||||
select: prismaSelect.value,
|
||||
});
|
||||
}
|
||||
|
||||
@Mutation(() => ViewSort)
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(UpdateViewSortAbilityHandler)
|
||||
async updateOneViewSort(
|
||||
@Args() args: UpdateOneViewSortArgs,
|
||||
@PrismaSelector({ modelName: 'ViewSort' })
|
||||
prismaSelect: PrismaSelect<'ViewSort'>,
|
||||
): Promise<Partial<ViewSort>> {
|
||||
return this.viewSortService.update({
|
||||
data: args.data,
|
||||
where: args.where,
|
||||
select: prismaSelect.value,
|
||||
} as Prisma.ViewSortUpdateArgs);
|
||||
}
|
||||
|
||||
@Mutation(() => AffectedRows, {
|
||||
nullable: false,
|
||||
})
|
||||
@UseGuards(AbilityGuard)
|
||||
@CheckAbilities(DeleteViewSortAbilityHandler)
|
||||
async deleteManyViewSort(
|
||||
@Args() args: DeleteManyViewSortArgs,
|
||||
): Promise<AffectedRows> {
|
||||
return this.viewSortService.deleteMany({
|
||||
where: args.where,
|
||||
});
|
||||
}
|
||||
}
|
28
server/src/core/view/services/view-sort.service.spec.ts
Normal file
28
server/src/core/view/services/view-sort.service.spec.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
import { prismaMock } from 'src/database/client-mock/jest-prisma-singleton';
|
||||
|
||||
import { ViewSortService } from './view-sort.service';
|
||||
|
||||
describe('ViewSortService', () => {
|
||||
let service: ViewSortService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
ViewSortService,
|
||||
{
|
||||
provide: PrismaService,
|
||||
useValue: prismaMock,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ViewSortService>(ViewSortService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
39
server/src/core/view/services/view-sort.service.ts
Normal file
39
server/src/core/view/services/view-sort.service.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { PrismaService } from 'src/database/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class ViewSortService {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
// Find
|
||||
findFirst = this.prismaService.client.viewSort.findFirst;
|
||||
findFirstOrThrow = this.prismaService.client.viewSort.findFirstOrThrow;
|
||||
|
||||
findUnique = this.prismaService.client.viewSort.findUnique;
|
||||
findUniqueOrThrow = this.prismaService.client.viewSort.findUniqueOrThrow;
|
||||
|
||||
findMany = this.prismaService.client.viewSort.findMany;
|
||||
|
||||
// Create
|
||||
create = this.prismaService.client.viewSort.create;
|
||||
createMany = this.prismaService.client.viewSort.createMany;
|
||||
|
||||
// Update
|
||||
update = this.prismaService.client.viewSort.update;
|
||||
upsert = this.prismaService.client.viewSort.upsert;
|
||||
updateMany = this.prismaService.client.viewSort.updateMany;
|
||||
|
||||
// Delete
|
||||
delete = this.prismaService.client.viewSort.delete;
|
||||
deleteMany = this.prismaService.client.viewSort.deleteMany;
|
||||
|
||||
// Aggregate
|
||||
aggregate = this.prismaService.client.viewSort.aggregate;
|
||||
|
||||
// Count
|
||||
count = this.prismaService.client.viewSort.count;
|
||||
|
||||
// GroupBy
|
||||
groupBy = this.prismaService.client.viewSort.groupBy;
|
||||
}
|
@ -2,8 +2,15 @@ import { Module } from '@nestjs/common';
|
||||
|
||||
import { ViewFieldService } from './services/view-field.service';
|
||||
import { ViewFieldResolver } from './resolvers/view-field.resolver';
|
||||
import { ViewSortService } from './services/view-sort.service';
|
||||
import { ViewSortResolver } from './resolvers/view-sort.resolver';
|
||||
|
||||
@Module({
|
||||
providers: [ViewFieldService, ViewFieldResolver],
|
||||
providers: [
|
||||
ViewFieldService,
|
||||
ViewSortService,
|
||||
ViewFieldResolver,
|
||||
ViewSortResolver,
|
||||
],
|
||||
})
|
||||
export class ViewModule {}
|
||||
|
@ -111,7 +111,9 @@ export class WorkspaceService {
|
||||
comment,
|
||||
activityTarget,
|
||||
activity,
|
||||
view,
|
||||
viewField,
|
||||
viewSort,
|
||||
} = this.prismaService.client;
|
||||
|
||||
const activitys = await activity.findMany({
|
||||
@ -151,9 +153,15 @@ export class WorkspaceService {
|
||||
activity.deleteMany({
|
||||
where,
|
||||
}),
|
||||
view.deleteMany({
|
||||
where,
|
||||
}),
|
||||
viewField.deleteMany({
|
||||
where,
|
||||
}),
|
||||
viewSort.deleteMany({
|
||||
where,
|
||||
}),
|
||||
refreshToken.deleteMany({
|
||||
where: { userId },
|
||||
}),
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[workspaceId,viewId,objectName,fieldName]` on the table `viewFields` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ViewType" AS ENUM ('Table', 'Pipeline');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "viewFields" ADD COLUMN "viewId" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "views" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"objectId" TEXT NOT NULL,
|
||||
"type" "ViewType" NOT NULL,
|
||||
"workspaceId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "views_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "views_workspaceId_type_objectId_name_key" ON "views"("workspaceId", "type", "objectId", "name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "viewFields_workspaceId_viewId_objectName_fieldName_key" ON "viewFields"("workspaceId", "viewId", "objectName", "fieldName");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "pipeline_progresses" ADD CONSTRAINT "pipeline_progresses_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "pipeline_progresses" ADD CONSTRAINT "pipeline_progresses_personId_fkey" FOREIGN KEY ("personId") REFERENCES "people"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "views" ADD CONSTRAINT "views_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "viewFields" ADD CONSTRAINT "viewFields_viewId_fkey" FOREIGN KEY ("viewId") REFERENCES "views"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
@ -0,0 +1,19 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ViewSortDirection" AS ENUM ('asc', 'desc');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "viewSorts" (
|
||||
"direction" "ViewSortDirection" NOT NULL,
|
||||
"key" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"viewId" TEXT NOT NULL,
|
||||
"workspaceId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "viewSorts_pkey" PRIMARY KEY ("viewId","key")
|
||||
);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "viewSorts" ADD CONSTRAINT "viewSorts_viewId_fkey" FOREIGN KEY ("viewId") REFERENCES "views"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "viewSorts" ADD CONSTRAINT "viewSorts_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
@ -174,6 +174,8 @@ model Workspace {
|
||||
pipelineProgresses PipelineProgress[]
|
||||
activityTargets ActivityTarget[]
|
||||
viewFields ViewField[]
|
||||
views View[]
|
||||
viewSorts ViewSort[]
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
deletedAt DateTime?
|
||||
@ -266,7 +268,7 @@ model Person {
|
||||
linkedinUrl String?
|
||||
/// @Validator.IsString()
|
||||
/// @Validator.IsOptional()
|
||||
xUrl String?
|
||||
xUrl String?
|
||||
/// @Validator.IsString()
|
||||
/// @Validator.IsOptional()
|
||||
jobTitle String?
|
||||
@ -557,6 +559,53 @@ model Attachment {
|
||||
@@map("attachments")
|
||||
}
|
||||
|
||||
enum ViewType {
|
||||
Table
|
||||
Pipeline
|
||||
}
|
||||
|
||||
model View {
|
||||
/// @Validator.IsString()
|
||||
/// @Validator.IsOptional()
|
||||
id String @id @default(uuid())
|
||||
|
||||
fields ViewField[]
|
||||
name String
|
||||
objectId String
|
||||
sorts ViewSort[]
|
||||
type ViewType
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspaceId String
|
||||
|
||||
@@unique([workspaceId, type, objectId, name])
|
||||
@@map("views")
|
||||
}
|
||||
|
||||
enum ViewSortDirection {
|
||||
asc
|
||||
desc
|
||||
}
|
||||
|
||||
model ViewSort {
|
||||
direction ViewSortDirection
|
||||
key String
|
||||
name String
|
||||
|
||||
view View @relation(fields: [viewId], references: [id])
|
||||
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("viewSorts")
|
||||
}
|
||||
|
||||
model ViewField {
|
||||
/// @Validator.IsString()
|
||||
/// @Validator.IsOptional()
|
||||
@ -568,10 +617,14 @@ model ViewField {
|
||||
objectName String
|
||||
sizeInPx Int
|
||||
|
||||
view View? @relation(fields: [viewId], references: [id])
|
||||
viewId String?
|
||||
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id])
|
||||
/// @TypeGraphQL.omit(input: true, output: true)
|
||||
workspaceId String
|
||||
|
||||
@@unique([workspaceId, viewId, objectName, fieldName])
|
||||
@@map("viewFields")
|
||||
}
|
||||
|
@ -16,5 +16,7 @@ export type ModelSelectMap = {
|
||||
PipelineStage: Prisma.PipelineStageSelect;
|
||||
PipelineProgress: Prisma.PipelineProgressSelect;
|
||||
Attachment: Prisma.AttachmentSelect;
|
||||
View: Prisma.ViewSelect;
|
||||
ViewSort: Prisma.ViewSortSelect;
|
||||
ViewField: Prisma.ViewFieldSelect;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user