Add "show company / people" view and "Notes" concept (#528)
* Begin adding show view and refactoring threads to become notes * Progress on design * Progress redesign timeline * Dropdown button, design improvement * Open comment thread edit mode in drawer * Autosave local storage and commentThreadcount * Improve display and fix missing key issue * Remove some hardcoded CSS properties * Create button * Split company show into ui/business + fix eslint * Fix font weight * Begin auto-save on edit mode * Save server-side query result to Apollo cache * Fix save behavior * Refetch timeline after creating note * Rename createCommentThreadWithComment * Improve styling * Revert "Improve styling" This reverts commit 9fbbf2db006e529330edc64f3eb8ff9ecdde6bb0. * Improve CSS styling * Bring back border radius inadvertently removed * padding adjustment * Improve blocknote design * Improve edit mode display * Remove Comments.tsx * Remove irrelevant comment stories * Removed un-necessary panel component * stop using fragment, move trash icon * Add a basic story for CompanyShow * Add a basic People show view * Fix storybook tests * Add very basic Person story * Refactor PR1 * Refactor part 2 * Refactor part 3 * Refactor part 4 * Fix tests --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -31,6 +31,7 @@
|
|||||||
"!javascript",
|
"!javascript",
|
||||||
"!json",
|
"!json",
|
||||||
"!typescript",
|
"!typescript",
|
||||||
|
"!typescriptreact",
|
||||||
"md",
|
"md",
|
||||||
"mdx"
|
"mdx"
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,12 +1,24 @@
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
devServer: {
|
||||||
|
client: {
|
||||||
|
overlay: {
|
||||||
|
runtimeErrors: (error) => {
|
||||||
|
if (error.message === "ResizeObserver loop limit exceeded") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
alias: {
|
alias: {
|
||||||
'~': path.resolve(__dirname, 'src'),
|
'~': path.resolve(__dirname, 'src'),
|
||||||
'@': path.resolve(__dirname, 'src/modules'),
|
'@': path.resolve(__dirname, 'src/modules'),
|
||||||
'@testing': path.resolve(__dirname, 'src/testing'),
|
'@testing': path.resolve(__dirname, 'src/testing'),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
jest: {
|
jest: {
|
||||||
configure: {
|
configure: {
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.7.5",
|
"@apollo/client": "^3.7.5",
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
|
"@blocknote/core": "^0.8.2",
|
||||||
|
"@blocknote/react": "^0.8.2",
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
"@floating-ui/react": "^0.24.3",
|
"@floating-ui/react": "^0.24.3",
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import { People } from '~/pages/people/People';
|
|||||||
import { SettingsProfile } from '~/pages/settings/SettingsProfile';
|
import { SettingsProfile } from '~/pages/settings/SettingsProfile';
|
||||||
import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers';
|
import { SettingsWorkspaceMembers } from '~/pages/settings/SettingsWorkspaceMembers';
|
||||||
|
|
||||||
|
import { CompanyShow } from './pages/companies/CompanyShow';
|
||||||
|
import { PersonShow } from './pages/people/PersonShow';
|
||||||
import { AppInternalHooks } from './AppInternalHooks';
|
import { AppInternalHooks } from './AppInternalHooks';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +67,13 @@ export function App() {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route path="" element={<Navigate to="/people" replace />} />
|
<Route path="" element={<Navigate to="/people" replace />} />
|
||||||
<Route path="people" element={<People />} />
|
<Route path="people" element={<People />} />
|
||||||
|
<Route path="person/:personId" element={<PersonShow />} />
|
||||||
<Route path="companies" element={<Companies />} />
|
<Route path="companies" element={<Companies />} />
|
||||||
|
<Route
|
||||||
|
path="companies/:companyId"
|
||||||
|
element={<CompanyShow />}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route path="opportunities" element={<Opportunities />} />
|
<Route path="opportunities" element={<Opportunities />} />
|
||||||
<Route
|
<Route
|
||||||
path="settings/*"
|
path="settings/*"
|
||||||
|
|||||||
@ -206,24 +206,47 @@ export type CommentScalarWhereInput = {
|
|||||||
|
|
||||||
export type CommentThread = {
|
export type CommentThread = {
|
||||||
__typename?: 'CommentThread';
|
__typename?: 'CommentThread';
|
||||||
|
author: User;
|
||||||
|
authorId: Scalars['String'];
|
||||||
|
body?: Maybe<Scalars['String']>;
|
||||||
commentThreadTargets?: Maybe<Array<CommentThreadTarget>>;
|
commentThreadTargets?: Maybe<Array<CommentThreadTarget>>;
|
||||||
comments?: Maybe<Array<Comment>>;
|
comments?: Maybe<Array<Comment>>;
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
|
title?: Maybe<Scalars['String']>;
|
||||||
updatedAt: Scalars['DateTime'];
|
updatedAt: Scalars['DateTime'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadCreateInput = {
|
export type CommentThreadCreateInput = {
|
||||||
|
author: UserCreateNestedOneWithoutCommentThreadInput;
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
||||||
comments?: InputMaybe<CommentCreateNestedManyWithoutCommentThreadInput>;
|
comments?: InputMaybe<CommentCreateNestedManyWithoutCommentThreadInput>;
|
||||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadCreateManyWorkspaceInput = {
|
export type CommentThreadCreateManyAuthorInput = {
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateManyAuthorInputEnvelope = {
|
||||||
|
data: Array<CommentThreadCreateManyAuthorInput>;
|
||||||
|
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateManyWorkspaceInput = {
|
||||||
|
authorId: Scalars['String'];
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -232,10 +255,22 @@ export type CommentThreadCreateManyWorkspaceInputEnvelope = {
|
|||||||
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
skipDuplicates?: InputMaybe<Scalars['Boolean']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateNestedManyWithoutAuthorInput = {
|
||||||
|
connect?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
|
connectOrCreate?: InputMaybe<Array<CommentThreadCreateOrConnectWithoutAuthorInput>>;
|
||||||
|
create?: InputMaybe<Array<CommentThreadCreateWithoutAuthorInput>>;
|
||||||
|
createMany?: InputMaybe<CommentThreadCreateManyAuthorInputEnvelope>;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadCreateNestedOneWithoutCommentsInput = {
|
export type CommentThreadCreateNestedOneWithoutCommentsInput = {
|
||||||
connect?: InputMaybe<CommentThreadWhereUniqueInput>;
|
connect?: InputMaybe<CommentThreadWhereUniqueInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateOrConnectWithoutAuthorInput = {
|
||||||
|
create: CommentThreadCreateWithoutAuthorInput;
|
||||||
|
where: CommentThreadWhereUniqueInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadCreateOrConnectWithoutCommentsInput = {
|
export type CommentThreadCreateOrConnectWithoutCommentsInput = {
|
||||||
create: CommentThreadCreateWithoutCommentsInput;
|
create: CommentThreadCreateWithoutCommentsInput;
|
||||||
where: CommentThreadWhereUniqueInput;
|
where: CommentThreadWhereUniqueInput;
|
||||||
@ -246,26 +281,56 @@ export type CommentThreadCreateOrConnectWithoutWorkspaceInput = {
|
|||||||
where: CommentThreadWhereUniqueInput;
|
where: CommentThreadWhereUniqueInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadCreateWithoutCommentsInput = {
|
export type CommentThreadCreateWithoutAuthorInput = {
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
body?: InputMaybe<Scalars['String']>;
|
||||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
id?: InputMaybe<Scalars['String']>;
|
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CommentThreadCreateWithoutWorkspaceInput = {
|
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
||||||
comments?: InputMaybe<CommentCreateNestedManyWithoutCommentThreadInput>;
|
comments?: InputMaybe<CommentCreateNestedManyWithoutCommentThreadInput>;
|
||||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateWithoutCommentsInput = {
|
||||||
|
author: UserCreateNestedOneWithoutCommentThreadInput;
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
|
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
||||||
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadCreateWithoutWorkspaceInput = {
|
||||||
|
author: UserCreateNestedOneWithoutCommentThreadInput;
|
||||||
|
body?: InputMaybe<Scalars['String']>;
|
||||||
|
commentThreadTargets?: InputMaybe<CommentThreadTargetCreateNestedManyWithoutCommentThreadInput>;
|
||||||
|
comments?: InputMaybe<CommentCreateNestedManyWithoutCommentThreadInput>;
|
||||||
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadListRelationFilter = {
|
||||||
|
every?: InputMaybe<CommentThreadWhereInput>;
|
||||||
|
none?: InputMaybe<CommentThreadWhereInput>;
|
||||||
|
some?: InputMaybe<CommentThreadWhereInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadOrderByRelationAggregateInput = {
|
||||||
|
_count?: InputMaybe<SortOrder>;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadOrderByWithRelationInput = {
|
export type CommentThreadOrderByWithRelationInput = {
|
||||||
|
author?: InputMaybe<UserOrderByWithRelationInput>;
|
||||||
|
authorId?: InputMaybe<SortOrder>;
|
||||||
|
body?: InputMaybe<SortOrder>;
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetOrderByRelationAggregateInput>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetOrderByRelationAggregateInput>;
|
||||||
comments?: InputMaybe<CommentOrderByRelationAggregateInput>;
|
comments?: InputMaybe<CommentOrderByRelationAggregateInput>;
|
||||||
createdAt?: InputMaybe<SortOrder>;
|
createdAt?: InputMaybe<SortOrder>;
|
||||||
id?: InputMaybe<SortOrder>;
|
id?: InputMaybe<SortOrder>;
|
||||||
|
title?: InputMaybe<SortOrder>;
|
||||||
updatedAt?: InputMaybe<SortOrder>;
|
updatedAt?: InputMaybe<SortOrder>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -275,9 +340,12 @@ export type CommentThreadRelationFilter = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export enum CommentThreadScalarFieldEnum {
|
export enum CommentThreadScalarFieldEnum {
|
||||||
|
AuthorId = 'authorId',
|
||||||
|
Body = 'body',
|
||||||
CreatedAt = 'createdAt',
|
CreatedAt = 'createdAt',
|
||||||
DeletedAt = 'deletedAt',
|
DeletedAt = 'deletedAt',
|
||||||
Id = 'id',
|
Id = 'id',
|
||||||
|
Title = 'title',
|
||||||
UpdatedAt = 'updatedAt',
|
UpdatedAt = 'updatedAt',
|
||||||
WorkspaceId = 'workspaceId'
|
WorkspaceId = 'workspaceId'
|
||||||
}
|
}
|
||||||
@ -286,8 +354,11 @@ export type CommentThreadScalarWhereInput = {
|
|||||||
AND?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
AND?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
||||||
NOT?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
NOT?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
||||||
OR?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
OR?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
||||||
|
authorId?: InputMaybe<StringFilter>;
|
||||||
|
body?: InputMaybe<StringNullableFilter>;
|
||||||
createdAt?: InputMaybe<DateTimeFilter>;
|
createdAt?: InputMaybe<DateTimeFilter>;
|
||||||
id?: InputMaybe<StringFilter>;
|
id?: InputMaybe<StringFilter>;
|
||||||
|
title?: InputMaybe<StringNullableFilter>;
|
||||||
updatedAt?: InputMaybe<DateTimeFilter>;
|
updatedAt?: InputMaybe<DateTimeFilter>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -418,24 +489,48 @@ export type CommentThreadTargetWhereUniqueInput = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateInput = {
|
export type CommentThreadUpdateInput = {
|
||||||
|
author?: InputMaybe<UserUpdateOneRequiredWithoutCommentThreadNestedInput>;
|
||||||
|
body?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
comments?: InputMaybe<CommentUpdateManyWithoutCommentThreadNestedInput>;
|
comments?: InputMaybe<CommentUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
title?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateManyMutationInput = {
|
export type CommentThreadUpdateManyMutationInput = {
|
||||||
|
body?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
title?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpdateManyWithWhereWithoutAuthorInput = {
|
||||||
|
data: CommentThreadUpdateManyMutationInput;
|
||||||
|
where: CommentThreadScalarWhereInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateManyWithWhereWithoutWorkspaceInput = {
|
export type CommentThreadUpdateManyWithWhereWithoutWorkspaceInput = {
|
||||||
data: CommentThreadUpdateManyMutationInput;
|
data: CommentThreadUpdateManyMutationInput;
|
||||||
where: CommentThreadScalarWhereInput;
|
where: CommentThreadScalarWhereInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpdateManyWithoutAuthorNestedInput = {
|
||||||
|
connect?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
|
connectOrCreate?: InputMaybe<Array<CommentThreadCreateOrConnectWithoutAuthorInput>>;
|
||||||
|
create?: InputMaybe<Array<CommentThreadCreateWithoutAuthorInput>>;
|
||||||
|
createMany?: InputMaybe<CommentThreadCreateManyAuthorInputEnvelope>;
|
||||||
|
delete?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
|
deleteMany?: InputMaybe<Array<CommentThreadScalarWhereInput>>;
|
||||||
|
disconnect?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
|
set?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
|
update?: InputMaybe<Array<CommentThreadUpdateWithWhereUniqueWithoutAuthorInput>>;
|
||||||
|
updateMany?: InputMaybe<Array<CommentThreadUpdateManyWithWhereWithoutAuthorInput>>;
|
||||||
|
upsert?: InputMaybe<Array<CommentThreadUpsertWithWhereUniqueWithoutAuthorInput>>;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateManyWithoutWorkspaceNestedInput = {
|
export type CommentThreadUpdateManyWithoutWorkspaceNestedInput = {
|
||||||
connect?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
connect?: InputMaybe<Array<CommentThreadWhereUniqueInput>>;
|
||||||
connectOrCreate?: InputMaybe<Array<CommentThreadCreateOrConnectWithoutWorkspaceInput>>;
|
connectOrCreate?: InputMaybe<Array<CommentThreadCreateOrConnectWithoutWorkspaceInput>>;
|
||||||
@ -458,26 +553,53 @@ export type CommentThreadUpdateOneRequiredWithoutCommentsNestedInput = {
|
|||||||
upsert?: InputMaybe<CommentThreadUpsertWithoutCommentsInput>;
|
upsert?: InputMaybe<CommentThreadUpsertWithoutCommentsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpdateWithWhereUniqueWithoutAuthorInput = {
|
||||||
|
data: CommentThreadUpdateWithoutAuthorInput;
|
||||||
|
where: CommentThreadWhereUniqueInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateWithWhereUniqueWithoutWorkspaceInput = {
|
export type CommentThreadUpdateWithWhereUniqueWithoutWorkspaceInput = {
|
||||||
data: CommentThreadUpdateWithoutWorkspaceInput;
|
data: CommentThreadUpdateWithoutWorkspaceInput;
|
||||||
where: CommentThreadWhereUniqueInput;
|
where: CommentThreadWhereUniqueInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CommentThreadUpdateWithoutCommentsInput = {
|
export type CommentThreadUpdateWithoutAuthorInput = {
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
body?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
|
||||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
|
||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CommentThreadUpdateWithoutWorkspaceInput = {
|
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
comments?: InputMaybe<CommentUpdateManyWithoutCommentThreadNestedInput>;
|
comments?: InputMaybe<CommentUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
title?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpdateWithoutCommentsInput = {
|
||||||
|
author?: InputMaybe<UserUpdateOneRequiredWithoutCommentThreadNestedInput>;
|
||||||
|
body?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
title?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpdateWithoutWorkspaceInput = {
|
||||||
|
author?: InputMaybe<UserUpdateOneRequiredWithoutCommentThreadNestedInput>;
|
||||||
|
body?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
commentThreadTargets?: InputMaybe<CommentThreadTargetUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
|
comments?: InputMaybe<CommentUpdateManyWithoutCommentThreadNestedInput>;
|
||||||
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
title?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CommentThreadUpsertWithWhereUniqueWithoutAuthorInput = {
|
||||||
|
create: CommentThreadCreateWithoutAuthorInput;
|
||||||
|
update: CommentThreadUpdateWithoutAuthorInput;
|
||||||
|
where: CommentThreadWhereUniqueInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type CommentThreadUpsertWithWhereUniqueWithoutWorkspaceInput = {
|
export type CommentThreadUpsertWithWhereUniqueWithoutWorkspaceInput = {
|
||||||
create: CommentThreadCreateWithoutWorkspaceInput;
|
create: CommentThreadCreateWithoutWorkspaceInput;
|
||||||
update: CommentThreadUpdateWithoutWorkspaceInput;
|
update: CommentThreadUpdateWithoutWorkspaceInput;
|
||||||
@ -493,10 +615,14 @@ export type CommentThreadWhereInput = {
|
|||||||
AND?: InputMaybe<Array<CommentThreadWhereInput>>;
|
AND?: InputMaybe<Array<CommentThreadWhereInput>>;
|
||||||
NOT?: InputMaybe<Array<CommentThreadWhereInput>>;
|
NOT?: InputMaybe<Array<CommentThreadWhereInput>>;
|
||||||
OR?: InputMaybe<Array<CommentThreadWhereInput>>;
|
OR?: InputMaybe<Array<CommentThreadWhereInput>>;
|
||||||
|
author?: InputMaybe<UserRelationFilter>;
|
||||||
|
authorId?: InputMaybe<StringFilter>;
|
||||||
|
body?: InputMaybe<StringNullableFilter>;
|
||||||
commentThreadTargets?: InputMaybe<CommentThreadTargetListRelationFilter>;
|
commentThreadTargets?: InputMaybe<CommentThreadTargetListRelationFilter>;
|
||||||
comments?: InputMaybe<CommentListRelationFilter>;
|
comments?: InputMaybe<CommentListRelationFilter>;
|
||||||
createdAt?: InputMaybe<DateTimeFilter>;
|
createdAt?: InputMaybe<DateTimeFilter>;
|
||||||
id?: InputMaybe<StringFilter>;
|
id?: InputMaybe<StringFilter>;
|
||||||
|
title?: InputMaybe<StringNullableFilter>;
|
||||||
updatedAt?: InputMaybe<DateTimeFilter>;
|
updatedAt?: InputMaybe<DateTimeFilter>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -651,7 +777,7 @@ export enum CommentableType {
|
|||||||
|
|
||||||
export type Company = {
|
export type Company = {
|
||||||
__typename?: 'Company';
|
__typename?: 'Company';
|
||||||
_commentCount: Scalars['Int'];
|
_commentThreadCount: Scalars['Int'];
|
||||||
accountOwner?: Maybe<User>;
|
accountOwner?: Maybe<User>;
|
||||||
accountOwnerId?: Maybe<Scalars['String']>;
|
accountOwnerId?: Maybe<Scalars['String']>;
|
||||||
address: Scalars['String'];
|
address: Scalars['String'];
|
||||||
@ -1270,13 +1396,14 @@ export type NullableStringFieldUpdateOperationsInput = {
|
|||||||
|
|
||||||
export type Person = {
|
export type Person = {
|
||||||
__typename?: 'Person';
|
__typename?: 'Person';
|
||||||
_commentCount: Scalars['Int'];
|
_commentThreadCount: Scalars['Int'];
|
||||||
city: Scalars['String'];
|
city: Scalars['String'];
|
||||||
commentThreads: Array<CommentThread>;
|
commentThreads: Array<CommentThread>;
|
||||||
comments: Array<Comment>;
|
comments: Array<Comment>;
|
||||||
company?: Maybe<Company>;
|
company?: Maybe<Company>;
|
||||||
companyId?: Maybe<Scalars['String']>;
|
companyId?: Maybe<Scalars['String']>;
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
|
displayName: Scalars['String'];
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
firstName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
@ -2303,6 +2430,8 @@ export type Query = {
|
|||||||
findManyPipelineProgress: Array<PipelineProgress>;
|
findManyPipelineProgress: Array<PipelineProgress>;
|
||||||
findManyPipelineStage: Array<PipelineStage>;
|
findManyPipelineStage: Array<PipelineStage>;
|
||||||
findManyUser: Array<User>;
|
findManyUser: Array<User>;
|
||||||
|
findUniqueCompany: Company;
|
||||||
|
findUniquePerson: Person;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2380,6 +2509,16 @@ export type QueryFindManyUserArgs = {
|
|||||||
where?: InputMaybe<UserWhereInput>;
|
where?: InputMaybe<UserWhereInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type QueryFindUniqueCompanyArgs = {
|
||||||
|
id: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type QueryFindUniquePersonArgs = {
|
||||||
|
id: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
export enum QueryMode {
|
export enum QueryMode {
|
||||||
Default = 'default',
|
Default = 'default',
|
||||||
Insensitive = 'insensitive'
|
Insensitive = 'insensitive'
|
||||||
@ -2432,6 +2571,7 @@ export type Telemetry = {
|
|||||||
|
|
||||||
export type User = {
|
export type User = {
|
||||||
__typename?: 'User';
|
__typename?: 'User';
|
||||||
|
CommentThread?: Maybe<Array<CommentThread>>;
|
||||||
avatarUrl?: Maybe<Scalars['String']>;
|
avatarUrl?: Maybe<Scalars['String']>;
|
||||||
comments?: Maybe<Array<Comment>>;
|
comments?: Maybe<Array<Comment>>;
|
||||||
companies?: Maybe<Array<Company>>;
|
companies?: Maybe<Array<Company>>;
|
||||||
@ -2451,6 +2591,12 @@ export type User = {
|
|||||||
workspaceMember?: Maybe<WorkspaceMember>;
|
workspaceMember?: Maybe<WorkspaceMember>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserCreateNestedOneWithoutCommentThreadInput = {
|
||||||
|
connect?: InputMaybe<UserWhereUniqueInput>;
|
||||||
|
connectOrCreate?: InputMaybe<UserCreateOrConnectWithoutCommentThreadInput>;
|
||||||
|
create?: InputMaybe<UserCreateWithoutCommentThreadInput>;
|
||||||
|
};
|
||||||
|
|
||||||
export type UserCreateNestedOneWithoutCommentsInput = {
|
export type UserCreateNestedOneWithoutCommentsInput = {
|
||||||
connect?: InputMaybe<UserWhereUniqueInput>;
|
connect?: InputMaybe<UserWhereUniqueInput>;
|
||||||
};
|
};
|
||||||
@ -2465,6 +2611,11 @@ export type UserCreateNestedOneWithoutWorkspaceMemberInput = {
|
|||||||
create?: InputMaybe<UserCreateWithoutWorkspaceMemberInput>;
|
create?: InputMaybe<UserCreateWithoutWorkspaceMemberInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserCreateOrConnectWithoutCommentThreadInput = {
|
||||||
|
create: UserCreateWithoutCommentThreadInput;
|
||||||
|
where: UserWhereUniqueInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type UserCreateOrConnectWithoutCommentsInput = {
|
export type UserCreateOrConnectWithoutCommentsInput = {
|
||||||
create: UserCreateWithoutCommentsInput;
|
create: UserCreateWithoutCommentsInput;
|
||||||
where: UserWhereUniqueInput;
|
where: UserWhereUniqueInput;
|
||||||
@ -2475,7 +2626,26 @@ export type UserCreateOrConnectWithoutWorkspaceMemberInput = {
|
|||||||
where: UserWhereUniqueInput;
|
where: UserWhereUniqueInput;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserCreateWithoutCommentThreadInput = {
|
||||||
|
avatarUrl?: InputMaybe<Scalars['String']>;
|
||||||
|
comments?: InputMaybe<CommentCreateNestedManyWithoutAuthorInput>;
|
||||||
|
companies?: InputMaybe<CompanyCreateNestedManyWithoutAccountOwnerInput>;
|
||||||
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
disabled?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
email: Scalars['String'];
|
||||||
|
emailVerified?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
firstName?: InputMaybe<Scalars['String']>;
|
||||||
|
id?: InputMaybe<Scalars['String']>;
|
||||||
|
lastName?: InputMaybe<Scalars['String']>;
|
||||||
|
lastSeen?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
locale: Scalars['String'];
|
||||||
|
metadata?: InputMaybe<Scalars['JSON']>;
|
||||||
|
phoneNumber?: InputMaybe<Scalars['String']>;
|
||||||
|
updatedAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
|
};
|
||||||
|
|
||||||
export type UserCreateWithoutCommentsInput = {
|
export type UserCreateWithoutCommentsInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadCreateNestedManyWithoutAuthorInput>;
|
||||||
avatarUrl?: InputMaybe<Scalars['String']>;
|
avatarUrl?: InputMaybe<Scalars['String']>;
|
||||||
companies?: InputMaybe<CompanyCreateNestedManyWithoutAccountOwnerInput>;
|
companies?: InputMaybe<CompanyCreateNestedManyWithoutAccountOwnerInput>;
|
||||||
createdAt?: InputMaybe<Scalars['DateTime']>;
|
createdAt?: InputMaybe<Scalars['DateTime']>;
|
||||||
@ -2493,6 +2663,7 @@ export type UserCreateWithoutCommentsInput = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type UserCreateWithoutWorkspaceMemberInput = {
|
export type UserCreateWithoutWorkspaceMemberInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadCreateNestedManyWithoutAuthorInput>;
|
||||||
avatarUrl?: InputMaybe<Scalars['String']>;
|
avatarUrl?: InputMaybe<Scalars['String']>;
|
||||||
comments?: InputMaybe<CommentCreateNestedManyWithoutAuthorInput>;
|
comments?: InputMaybe<CommentCreateNestedManyWithoutAuthorInput>;
|
||||||
companies?: InputMaybe<CompanyCreateNestedManyWithoutAccountOwnerInput>;
|
companies?: InputMaybe<CompanyCreateNestedManyWithoutAccountOwnerInput>;
|
||||||
@ -2516,6 +2687,7 @@ export type UserExists = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type UserOrderByWithRelationInput = {
|
export type UserOrderByWithRelationInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadOrderByRelationAggregateInput>;
|
||||||
avatarUrl?: InputMaybe<SortOrder>;
|
avatarUrl?: InputMaybe<SortOrder>;
|
||||||
comments?: InputMaybe<CommentOrderByRelationAggregateInput>;
|
comments?: InputMaybe<CommentOrderByRelationAggregateInput>;
|
||||||
companies?: InputMaybe<CompanyOrderByRelationAggregateInput>;
|
companies?: InputMaybe<CompanyOrderByRelationAggregateInput>;
|
||||||
@ -2557,6 +2729,7 @@ export enum UserScalarFieldEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type UserUpdateInput = {
|
export type UserUpdateInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadUpdateManyWithoutAuthorNestedInput>;
|
||||||
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
comments?: InputMaybe<CommentUpdateManyWithoutAuthorNestedInput>;
|
comments?: InputMaybe<CommentUpdateManyWithoutAuthorNestedInput>;
|
||||||
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
||||||
@ -2574,6 +2747,14 @@ export type UserUpdateInput = {
|
|||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserUpdateOneRequiredWithoutCommentThreadNestedInput = {
|
||||||
|
connect?: InputMaybe<UserWhereUniqueInput>;
|
||||||
|
connectOrCreate?: InputMaybe<UserCreateOrConnectWithoutCommentThreadInput>;
|
||||||
|
create?: InputMaybe<UserCreateWithoutCommentThreadInput>;
|
||||||
|
update?: InputMaybe<UserUpdateWithoutCommentThreadInput>;
|
||||||
|
upsert?: InputMaybe<UserUpsertWithoutCommentThreadInput>;
|
||||||
|
};
|
||||||
|
|
||||||
export type UserUpdateOneRequiredWithoutCommentsNestedInput = {
|
export type UserUpdateOneRequiredWithoutCommentsNestedInput = {
|
||||||
connect?: InputMaybe<UserWhereUniqueInput>;
|
connect?: InputMaybe<UserWhereUniqueInput>;
|
||||||
connectOrCreate?: InputMaybe<UserCreateOrConnectWithoutCommentsInput>;
|
connectOrCreate?: InputMaybe<UserCreateOrConnectWithoutCommentsInput>;
|
||||||
@ -2594,24 +2775,7 @@ export type UserUpdateOneWithoutCompaniesNestedInput = {
|
|||||||
connect?: InputMaybe<UserWhereUniqueInput>;
|
connect?: InputMaybe<UserWhereUniqueInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UserUpdateWithoutCommentsInput = {
|
export type UserUpdateWithoutCommentThreadInput = {
|
||||||
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
|
||||||
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
|
||||||
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
|
||||||
disabled?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
|
||||||
email?: InputMaybe<StringFieldUpdateOperationsInput>;
|
|
||||||
emailVerified?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
|
||||||
firstName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
|
||||||
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
|
||||||
lastName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
|
||||||
lastSeen?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
|
||||||
locale?: InputMaybe<StringFieldUpdateOperationsInput>;
|
|
||||||
metadata?: InputMaybe<Scalars['JSON']>;
|
|
||||||
phoneNumber?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
|
||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UserUpdateWithoutWorkspaceMemberInput = {
|
|
||||||
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
comments?: InputMaybe<CommentUpdateManyWithoutAuthorNestedInput>;
|
comments?: InputMaybe<CommentUpdateManyWithoutAuthorNestedInput>;
|
||||||
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
||||||
@ -2629,6 +2793,48 @@ export type UserUpdateWithoutWorkspaceMemberInput = {
|
|||||||
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type UserUpdateWithoutCommentsInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadUpdateManyWithoutAuthorNestedInput>;
|
||||||
|
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
||||||
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
disabled?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
||||||
|
email?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
emailVerified?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
||||||
|
firstName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
lastName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
lastSeen?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||||
|
locale?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
metadata?: InputMaybe<Scalars['JSON']>;
|
||||||
|
phoneNumber?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserUpdateWithoutWorkspaceMemberInput = {
|
||||||
|
CommentThread?: InputMaybe<CommentThreadUpdateManyWithoutAuthorNestedInput>;
|
||||||
|
avatarUrl?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
comments?: InputMaybe<CommentUpdateManyWithoutAuthorNestedInput>;
|
||||||
|
companies?: InputMaybe<CompanyUpdateManyWithoutAccountOwnerNestedInput>;
|
||||||
|
createdAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
disabled?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
||||||
|
email?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
emailVerified?: InputMaybe<BoolFieldUpdateOperationsInput>;
|
||||||
|
firstName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
id?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
lastName?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
lastSeen?: InputMaybe<NullableDateTimeFieldUpdateOperationsInput>;
|
||||||
|
locale?: InputMaybe<StringFieldUpdateOperationsInput>;
|
||||||
|
metadata?: InputMaybe<Scalars['JSON']>;
|
||||||
|
phoneNumber?: InputMaybe<NullableStringFieldUpdateOperationsInput>;
|
||||||
|
updatedAt?: InputMaybe<DateTimeFieldUpdateOperationsInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UserUpsertWithoutCommentThreadInput = {
|
||||||
|
create: UserCreateWithoutCommentThreadInput;
|
||||||
|
update: UserUpdateWithoutCommentThreadInput;
|
||||||
|
};
|
||||||
|
|
||||||
export type UserUpsertWithoutCommentsInput = {
|
export type UserUpsertWithoutCommentsInput = {
|
||||||
create: UserCreateWithoutCommentsInput;
|
create: UserCreateWithoutCommentsInput;
|
||||||
update: UserUpdateWithoutCommentsInput;
|
update: UserUpdateWithoutCommentsInput;
|
||||||
@ -2641,6 +2847,7 @@ export type UserUpsertWithoutWorkspaceMemberInput = {
|
|||||||
|
|
||||||
export type UserWhereInput = {
|
export type UserWhereInput = {
|
||||||
AND?: InputMaybe<Array<UserWhereInput>>;
|
AND?: InputMaybe<Array<UserWhereInput>>;
|
||||||
|
CommentThread?: InputMaybe<CommentThreadListRelationFilter>;
|
||||||
NOT?: InputMaybe<Array<UserWhereInput>>;
|
NOT?: InputMaybe<Array<UserWhereInput>>;
|
||||||
OR?: InputMaybe<Array<UserWhereInput>>;
|
OR?: InputMaybe<Array<UserWhereInput>>;
|
||||||
avatarUrl?: InputMaybe<StringNullableFilter>;
|
avatarUrl?: InputMaybe<StringNullableFilter>;
|
||||||
@ -2851,17 +3058,17 @@ export type CreateCommentMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type CreateCommentMutation = { __typename?: 'Mutation', createOneComment: { __typename?: 'Comment', id: string, createdAt: string, body: string, commentThreadId: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } } };
|
export type CreateCommentMutation = { __typename?: 'Mutation', createOneComment: { __typename?: 'Comment', id: string, createdAt: string, body: string, commentThreadId: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } } };
|
||||||
|
|
||||||
export type CreateCommentThreadWithCommentMutationVariables = Exact<{
|
export type CreateCommentThreadMutationVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
commentText: Scalars['String'];
|
body?: InputMaybe<Scalars['String']>;
|
||||||
|
title?: InputMaybe<Scalars['String']>;
|
||||||
authorId: Scalars['String'];
|
authorId: Scalars['String'];
|
||||||
createdAt: Scalars['DateTime'];
|
createdAt: Scalars['DateTime'];
|
||||||
commentId: Scalars['String'];
|
|
||||||
commentThreadTargetArray: Array<CommentThreadTargetCreateManyCommentThreadInput> | CommentThreadTargetCreateManyCommentThreadInput;
|
commentThreadTargetArray: Array<CommentThreadTargetCreateManyCommentThreadInput> | CommentThreadTargetCreateManyCommentThreadInput;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type CreateCommentThreadWithCommentMutation = { __typename?: 'Mutation', createOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentThreadId: string, commentableType: CommentableType, commentableId: string }> | null, comments?: Array<{ __typename?: 'Comment', id: string, createdAt: string, updatedAt: string, body: string, author: { __typename?: 'User', id: string } }> | null } };
|
export type CreateCommentThreadMutation = { __typename?: 'Mutation', createOneCommentThread: { __typename?: 'CommentThread', id: string, createdAt: string, updatedAt: string, authorId: string, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, createdAt: string, updatedAt: string, commentThreadId: string, commentableType: CommentableType, commentableId: string }> | null, comments?: Array<{ __typename?: 'Comment', id: string, createdAt: string, updatedAt: string, body: string, author: { __typename?: 'User', id: string } }> | null } };
|
||||||
|
|
||||||
export type GetCommentThreadsByTargetsQueryVariables = Exact<{
|
export type GetCommentThreadsByTargetsQueryVariables = Exact<{
|
||||||
commentThreadTargetIds: Array<Scalars['String']> | Scalars['String'];
|
commentThreadTargetIds: Array<Scalars['String']> | Scalars['String'];
|
||||||
@ -2869,14 +3076,14 @@ export type GetCommentThreadsByTargetsQueryVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCommentThreadsByTargetsQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
|
export type GetCommentThreadsByTargetsQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, title?: string | null, body?: string | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
|
||||||
|
|
||||||
export type GetCommentThreadQueryVariables = Exact<{
|
export type GetCommentThreadQueryVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', commentableId: string, commentableType: CommentableType }> | null }> };
|
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, body?: string | null, title?: string | null, author: { __typename?: 'User', id: string, firstName?: string | null, lastName?: string | null }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
|
||||||
|
|
||||||
export type AddCommentThreadTargetOnCommentThreadMutationVariables = Exact<{
|
export type AddCommentThreadTargetOnCommentThreadMutationVariables = Exact<{
|
||||||
commentThreadId: Scalars['String'];
|
commentThreadId: Scalars['String'];
|
||||||
@ -2904,13 +3111,36 @@ export type DeleteCommentThreadMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type DeleteCommentThreadMutation = { __typename?: 'Mutation', deleteManyCommentThreads: { __typename?: 'AffectedRows', count: number } };
|
export type DeleteCommentThreadMutation = { __typename?: 'Mutation', deleteManyCommentThreads: { __typename?: 'AffectedRows', count: number } };
|
||||||
|
|
||||||
|
export type UpdateCommentThreadTitleMutationVariables = Exact<{
|
||||||
|
commentThreadId: Scalars['String'];
|
||||||
|
commentThreadTitle?: InputMaybe<Scalars['String']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type UpdateCommentThreadTitleMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, title?: string | null } };
|
||||||
|
|
||||||
|
export type UpdateCommentThreadBodyMutationVariables = Exact<{
|
||||||
|
commentThreadId: Scalars['String'];
|
||||||
|
commentThreadBody?: InputMaybe<Scalars['String']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type UpdateCommentThreadBodyMutation = { __typename?: 'Mutation', updateOneCommentThread: { __typename?: 'CommentThread', id: string, body?: string | null } };
|
||||||
|
|
||||||
export type GetCompaniesQueryVariables = Exact<{
|
export type GetCompaniesQueryVariables = Exact<{
|
||||||
orderBy?: InputMaybe<Array<CompanyOrderByWithRelationInput> | CompanyOrderByWithRelationInput>;
|
orderBy?: InputMaybe<Array<CompanyOrderByWithRelationInput> | CompanyOrderByWithRelationInput>;
|
||||||
where?: InputMaybe<CompanyWhereInput>;
|
where?: InputMaybe<CompanyWhereInput>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetCompaniesQuery = { __typename?: 'Query', companies: Array<{ __typename?: 'Company', id: string, domainName: string, name: string, createdAt: string, address: string, employees?: number | null, _commentCount: number, accountOwner?: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null } | null }> };
|
export type GetCompaniesQuery = { __typename?: 'Query', companies: Array<{ __typename?: 'Company', id: string, domainName: string, name: string, createdAt: string, address: string, employees?: number | null, _commentThreadCount: number, accountOwner?: { __typename?: 'User', id: string, email: string, displayName: string, firstName?: string | null, lastName?: string | null } | null }> };
|
||||||
|
|
||||||
|
export type GetCompanyQueryVariables = Exact<{
|
||||||
|
id: Scalars['String'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type GetCompanyQuery = { __typename?: 'Query', findUniqueCompany: { __typename?: 'Company', id: string, domainName: string, name: string, createdAt: string, address: string, employees?: number | null, _commentThreadCount: number, accountOwner?: { __typename?: 'User', id: string, email: string, displayName: string } | null } };
|
||||||
|
|
||||||
export type UpdateCompanyMutationVariables = Exact<{
|
export type UpdateCompanyMutationVariables = Exact<{
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
@ -2951,7 +3181,14 @@ export type GetPeopleQueryVariables = Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type GetPeopleQuery = { __typename?: 'Query', people: Array<{ __typename?: 'Person', id: string, phone: string, email: string, city: string, firstName: string, lastName: string, createdAt: string, _commentCount: number, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null }> };
|
export type GetPeopleQuery = { __typename?: 'Query', people: Array<{ __typename?: 'Person', id: string, phone: string, email: string, city: string, firstName: string, lastName: string, createdAt: string, _commentThreadCount: number, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null }> };
|
||||||
|
|
||||||
|
export type GetPersonQueryVariables = Exact<{
|
||||||
|
id: Scalars['String'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type GetPersonQuery = { __typename?: 'Query', findUniquePerson: { __typename?: 'Person', id: string, firstName: string, lastName: string, displayName: string, createdAt: string } };
|
||||||
|
|
||||||
export type UpdatePeopleMutationVariables = Exact<{
|
export type UpdatePeopleMutationVariables = Exact<{
|
||||||
id?: InputMaybe<Scalars['String']>;
|
id?: InputMaybe<Scalars['String']>;
|
||||||
@ -3416,14 +3653,15 @@ export function useCreateCommentMutation(baseOptions?: Apollo.MutationHookOption
|
|||||||
export type CreateCommentMutationHookResult = ReturnType<typeof useCreateCommentMutation>;
|
export type CreateCommentMutationHookResult = ReturnType<typeof useCreateCommentMutation>;
|
||||||
export type CreateCommentMutationResult = Apollo.MutationResult<CreateCommentMutation>;
|
export type CreateCommentMutationResult = Apollo.MutationResult<CreateCommentMutation>;
|
||||||
export type CreateCommentMutationOptions = Apollo.BaseMutationOptions<CreateCommentMutation, CreateCommentMutationVariables>;
|
export type CreateCommentMutationOptions = Apollo.BaseMutationOptions<CreateCommentMutation, CreateCommentMutationVariables>;
|
||||||
export const CreateCommentThreadWithCommentDocument = gql`
|
export const CreateCommentThreadDocument = gql`
|
||||||
mutation CreateCommentThreadWithComment($commentThreadId: String!, $commentText: String!, $authorId: String!, $createdAt: DateTime!, $commentId: String!, $commentThreadTargetArray: [CommentThreadTargetCreateManyCommentThreadInput!]!) {
|
mutation CreateCommentThread($commentThreadId: String!, $body: String, $title: String, $authorId: String!, $createdAt: DateTime!, $commentThreadTargetArray: [CommentThreadTargetCreateManyCommentThreadInput!]!) {
|
||||||
createOneCommentThread(
|
createOneCommentThread(
|
||||||
data: {id: $commentThreadId, createdAt: $createdAt, updatedAt: $createdAt, comments: {createMany: {data: {authorId: $authorId, id: $commentId, createdAt: $createdAt, body: $commentText}}}, commentThreadTargets: {createMany: {data: $commentThreadTargetArray, skipDuplicates: true}}}
|
data: {id: $commentThreadId, createdAt: $createdAt, updatedAt: $createdAt, author: {connect: {id: $authorId}}, body: $body, title: $title, commentThreadTargets: {createMany: {data: $commentThreadTargetArray, skipDuplicates: true}}}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
|
authorId
|
||||||
commentThreadTargets {
|
commentThreadTargets {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
@ -3444,37 +3682,37 @@ export const CreateCommentThreadWithCommentDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export type CreateCommentThreadWithCommentMutationFn = Apollo.MutationFunction<CreateCommentThreadWithCommentMutation, CreateCommentThreadWithCommentMutationVariables>;
|
export type CreateCommentThreadMutationFn = Apollo.MutationFunction<CreateCommentThreadMutation, CreateCommentThreadMutationVariables>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __useCreateCommentThreadWithCommentMutation__
|
* __useCreateCommentThreadMutation__
|
||||||
*
|
*
|
||||||
* To run a mutation, you first call `useCreateCommentThreadWithCommentMutation` within a React component and pass it any options that fit your needs.
|
* To run a mutation, you first call `useCreateCommentThreadMutation` within a React component and pass it any options that fit your needs.
|
||||||
* When your component renders, `useCreateCommentThreadWithCommentMutation` returns a tuple that includes:
|
* When your component renders, `useCreateCommentThreadMutation` returns a tuple that includes:
|
||||||
* - A mutate function that you can call at any time to execute the mutation
|
* - A mutate function that you can call at any time to execute the mutation
|
||||||
* - An object with fields that represent the current status of the mutation's execution
|
* - An object with fields that represent the current status of the mutation's execution
|
||||||
*
|
*
|
||||||
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* const [createCommentThreadWithCommentMutation, { data, loading, error }] = useCreateCommentThreadWithCommentMutation({
|
* const [createCommentThreadMutation, { data, loading, error }] = useCreateCommentThreadMutation({
|
||||||
* variables: {
|
* variables: {
|
||||||
* commentThreadId: // value for 'commentThreadId'
|
* commentThreadId: // value for 'commentThreadId'
|
||||||
* commentText: // value for 'commentText'
|
* body: // value for 'body'
|
||||||
|
* title: // value for 'title'
|
||||||
* authorId: // value for 'authorId'
|
* authorId: // value for 'authorId'
|
||||||
* createdAt: // value for 'createdAt'
|
* createdAt: // value for 'createdAt'
|
||||||
* commentId: // value for 'commentId'
|
|
||||||
* commentThreadTargetArray: // value for 'commentThreadTargetArray'
|
* commentThreadTargetArray: // value for 'commentThreadTargetArray'
|
||||||
* },
|
* },
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function useCreateCommentThreadWithCommentMutation(baseOptions?: Apollo.MutationHookOptions<CreateCommentThreadWithCommentMutation, CreateCommentThreadWithCommentMutationVariables>) {
|
export function useCreateCommentThreadMutation(baseOptions?: Apollo.MutationHookOptions<CreateCommentThreadMutation, CreateCommentThreadMutationVariables>) {
|
||||||
const options = {...defaultOptions, ...baseOptions}
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
return Apollo.useMutation<CreateCommentThreadWithCommentMutation, CreateCommentThreadWithCommentMutationVariables>(CreateCommentThreadWithCommentDocument, options);
|
return Apollo.useMutation<CreateCommentThreadMutation, CreateCommentThreadMutationVariables>(CreateCommentThreadDocument, options);
|
||||||
}
|
}
|
||||||
export type CreateCommentThreadWithCommentMutationHookResult = ReturnType<typeof useCreateCommentThreadWithCommentMutation>;
|
export type CreateCommentThreadMutationHookResult = ReturnType<typeof useCreateCommentThreadMutation>;
|
||||||
export type CreateCommentThreadWithCommentMutationResult = Apollo.MutationResult<CreateCommentThreadWithCommentMutation>;
|
export type CreateCommentThreadMutationResult = Apollo.MutationResult<CreateCommentThreadMutation>;
|
||||||
export type CreateCommentThreadWithCommentMutationOptions = Apollo.BaseMutationOptions<CreateCommentThreadWithCommentMutation, CreateCommentThreadWithCommentMutationVariables>;
|
export type CreateCommentThreadMutationOptions = Apollo.BaseMutationOptions<CreateCommentThreadMutation, CreateCommentThreadMutationVariables>;
|
||||||
export const GetCommentThreadsByTargetsDocument = gql`
|
export const GetCommentThreadsByTargetsDocument = gql`
|
||||||
query GetCommentThreadsByTargets($commentThreadTargetIds: [String!]!, $orderBy: [CommentThreadOrderByWithRelationInput!]) {
|
query GetCommentThreadsByTargets($commentThreadTargetIds: [String!]!, $orderBy: [CommentThreadOrderByWithRelationInput!]) {
|
||||||
findManyCommentThreads(
|
findManyCommentThreads(
|
||||||
@ -3482,6 +3720,14 @@ export const GetCommentThreadsByTargetsDocument = gql`
|
|||||||
where: {commentThreadTargets: {some: {commentableId: {in: $commentThreadTargetIds}}}}
|
where: {commentThreadTargets: {some: {commentableId: {in: $commentThreadTargetIds}}}}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
createdAt
|
||||||
|
title
|
||||||
|
body
|
||||||
|
author {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
comments {
|
comments {
|
||||||
id
|
id
|
||||||
body
|
body
|
||||||
@ -3536,6 +3782,14 @@ export const GetCommentThreadDocument = gql`
|
|||||||
query GetCommentThread($commentThreadId: String!) {
|
query GetCommentThread($commentThreadId: String!) {
|
||||||
findManyCommentThreads(where: {id: {equals: $commentThreadId}}) {
|
findManyCommentThreads(where: {id: {equals: $commentThreadId}}) {
|
||||||
id
|
id
|
||||||
|
createdAt
|
||||||
|
body
|
||||||
|
title
|
||||||
|
author {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
comments {
|
comments {
|
||||||
id
|
id
|
||||||
body
|
body
|
||||||
@ -3550,6 +3804,7 @@ export const GetCommentThreadDocument = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
commentThreadTargets {
|
commentThreadTargets {
|
||||||
|
id
|
||||||
commentableId
|
commentableId
|
||||||
commentableType
|
commentableType
|
||||||
}
|
}
|
||||||
@ -3712,6 +3967,82 @@ export function useDeleteCommentThreadMutation(baseOptions?: Apollo.MutationHook
|
|||||||
export type DeleteCommentThreadMutationHookResult = ReturnType<typeof useDeleteCommentThreadMutation>;
|
export type DeleteCommentThreadMutationHookResult = ReturnType<typeof useDeleteCommentThreadMutation>;
|
||||||
export type DeleteCommentThreadMutationResult = Apollo.MutationResult<DeleteCommentThreadMutation>;
|
export type DeleteCommentThreadMutationResult = Apollo.MutationResult<DeleteCommentThreadMutation>;
|
||||||
export type DeleteCommentThreadMutationOptions = Apollo.BaseMutationOptions<DeleteCommentThreadMutation, DeleteCommentThreadMutationVariables>;
|
export type DeleteCommentThreadMutationOptions = Apollo.BaseMutationOptions<DeleteCommentThreadMutation, DeleteCommentThreadMutationVariables>;
|
||||||
|
export const UpdateCommentThreadTitleDocument = gql`
|
||||||
|
mutation UpdateCommentThreadTitle($commentThreadId: String!, $commentThreadTitle: String) {
|
||||||
|
updateOneCommentThread(
|
||||||
|
where: {id: $commentThreadId}
|
||||||
|
data: {title: {set: $commentThreadTitle}}
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type UpdateCommentThreadTitleMutationFn = Apollo.MutationFunction<UpdateCommentThreadTitleMutation, UpdateCommentThreadTitleMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useUpdateCommentThreadTitleMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useUpdateCommentThreadTitleMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useUpdateCommentThreadTitleMutation` 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 [updateCommentThreadTitleMutation, { data, loading, error }] = useUpdateCommentThreadTitleMutation({
|
||||||
|
* variables: {
|
||||||
|
* commentThreadId: // value for 'commentThreadId'
|
||||||
|
* commentThreadTitle: // value for 'commentThreadTitle'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useUpdateCommentThreadTitleMutation(baseOptions?: Apollo.MutationHookOptions<UpdateCommentThreadTitleMutation, UpdateCommentThreadTitleMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<UpdateCommentThreadTitleMutation, UpdateCommentThreadTitleMutationVariables>(UpdateCommentThreadTitleDocument, options);
|
||||||
|
}
|
||||||
|
export type UpdateCommentThreadTitleMutationHookResult = ReturnType<typeof useUpdateCommentThreadTitleMutation>;
|
||||||
|
export type UpdateCommentThreadTitleMutationResult = Apollo.MutationResult<UpdateCommentThreadTitleMutation>;
|
||||||
|
export type UpdateCommentThreadTitleMutationOptions = Apollo.BaseMutationOptions<UpdateCommentThreadTitleMutation, UpdateCommentThreadTitleMutationVariables>;
|
||||||
|
export const UpdateCommentThreadBodyDocument = gql`
|
||||||
|
mutation UpdateCommentThreadBody($commentThreadId: String!, $commentThreadBody: String) {
|
||||||
|
updateOneCommentThread(
|
||||||
|
where: {id: $commentThreadId}
|
||||||
|
data: {body: {set: $commentThreadBody}}
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type UpdateCommentThreadBodyMutationFn = Apollo.MutationFunction<UpdateCommentThreadBodyMutation, UpdateCommentThreadBodyMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useUpdateCommentThreadBodyMutation__
|
||||||
|
*
|
||||||
|
* To run a mutation, you first call `useUpdateCommentThreadBodyMutation` within a React component and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useUpdateCommentThreadBodyMutation` 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 [updateCommentThreadBodyMutation, { data, loading, error }] = useUpdateCommentThreadBodyMutation({
|
||||||
|
* variables: {
|
||||||
|
* commentThreadId: // value for 'commentThreadId'
|
||||||
|
* commentThreadBody: // value for 'commentThreadBody'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useUpdateCommentThreadBodyMutation(baseOptions?: Apollo.MutationHookOptions<UpdateCommentThreadBodyMutation, UpdateCommentThreadBodyMutationVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useMutation<UpdateCommentThreadBodyMutation, UpdateCommentThreadBodyMutationVariables>(UpdateCommentThreadBodyDocument, options);
|
||||||
|
}
|
||||||
|
export type UpdateCommentThreadBodyMutationHookResult = ReturnType<typeof useUpdateCommentThreadBodyMutation>;
|
||||||
|
export type UpdateCommentThreadBodyMutationResult = Apollo.MutationResult<UpdateCommentThreadBodyMutation>;
|
||||||
|
export type UpdateCommentThreadBodyMutationOptions = Apollo.BaseMutationOptions<UpdateCommentThreadBodyMutation, UpdateCommentThreadBodyMutationVariables>;
|
||||||
export const GetCompaniesDocument = gql`
|
export const GetCompaniesDocument = gql`
|
||||||
query GetCompanies($orderBy: [CompanyOrderByWithRelationInput!], $where: CompanyWhereInput) {
|
query GetCompanies($orderBy: [CompanyOrderByWithRelationInput!], $where: CompanyWhereInput) {
|
||||||
companies: findManyCompany(orderBy: $orderBy, where: $where) {
|
companies: findManyCompany(orderBy: $orderBy, where: $where) {
|
||||||
@ -3721,7 +4052,7 @@ export const GetCompaniesDocument = gql`
|
|||||||
createdAt
|
createdAt
|
||||||
address
|
address
|
||||||
employees
|
employees
|
||||||
_commentCount
|
_commentThreadCount
|
||||||
accountOwner {
|
accountOwner {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
@ -3761,6 +4092,52 @@ export function useGetCompaniesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptio
|
|||||||
export type GetCompaniesQueryHookResult = ReturnType<typeof useGetCompaniesQuery>;
|
export type GetCompaniesQueryHookResult = ReturnType<typeof useGetCompaniesQuery>;
|
||||||
export type GetCompaniesLazyQueryHookResult = ReturnType<typeof useGetCompaniesLazyQuery>;
|
export type GetCompaniesLazyQueryHookResult = ReturnType<typeof useGetCompaniesLazyQuery>;
|
||||||
export type GetCompaniesQueryResult = Apollo.QueryResult<GetCompaniesQuery, GetCompaniesQueryVariables>;
|
export type GetCompaniesQueryResult = Apollo.QueryResult<GetCompaniesQuery, GetCompaniesQueryVariables>;
|
||||||
|
export const GetCompanyDocument = gql`
|
||||||
|
query GetCompany($id: String!) {
|
||||||
|
findUniqueCompany(id: $id) {
|
||||||
|
id
|
||||||
|
domainName
|
||||||
|
name
|
||||||
|
createdAt
|
||||||
|
address
|
||||||
|
employees
|
||||||
|
_commentThreadCount
|
||||||
|
accountOwner {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useGetCompanyQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useGetCompanyQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useGetCompanyQuery` 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 } = useGetCompanyQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useGetCompanyQuery(baseOptions: Apollo.QueryHookOptions<GetCompanyQuery, GetCompanyQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<GetCompanyQuery, GetCompanyQueryVariables>(GetCompanyDocument, options);
|
||||||
|
}
|
||||||
|
export function useGetCompanyLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetCompanyQuery, GetCompanyQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<GetCompanyQuery, GetCompanyQueryVariables>(GetCompanyDocument, options);
|
||||||
|
}
|
||||||
|
export type GetCompanyQueryHookResult = ReturnType<typeof useGetCompanyQuery>;
|
||||||
|
export type GetCompanyLazyQueryHookResult = ReturnType<typeof useGetCompanyLazyQuery>;
|
||||||
|
export type GetCompanyQueryResult = Apollo.QueryResult<GetCompanyQuery, GetCompanyQueryVariables>;
|
||||||
export const UpdateCompanyDocument = gql`
|
export const UpdateCompanyDocument = gql`
|
||||||
mutation UpdateCompany($id: String, $name: String, $domainName: String, $accountOwnerId: String, $createdAt: DateTime, $address: String, $employees: Int) {
|
mutation UpdateCompany($id: String, $name: String, $domainName: String, $accountOwnerId: String, $createdAt: DateTime, $address: String, $employees: Int) {
|
||||||
updateOneCompany(
|
updateOneCompany(
|
||||||
@ -3903,7 +4280,7 @@ export const GetPeopleDocument = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
createdAt
|
createdAt
|
||||||
_commentCount
|
_commentThreadCount
|
||||||
company {
|
company {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@ -3942,6 +4319,45 @@ export function useGetPeopleLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<
|
|||||||
export type GetPeopleQueryHookResult = ReturnType<typeof useGetPeopleQuery>;
|
export type GetPeopleQueryHookResult = ReturnType<typeof useGetPeopleQuery>;
|
||||||
export type GetPeopleLazyQueryHookResult = ReturnType<typeof useGetPeopleLazyQuery>;
|
export type GetPeopleLazyQueryHookResult = ReturnType<typeof useGetPeopleLazyQuery>;
|
||||||
export type GetPeopleQueryResult = Apollo.QueryResult<GetPeopleQuery, GetPeopleQueryVariables>;
|
export type GetPeopleQueryResult = Apollo.QueryResult<GetPeopleQuery, GetPeopleQueryVariables>;
|
||||||
|
export const GetPersonDocument = gql`
|
||||||
|
query GetPerson($id: String!) {
|
||||||
|
findUniquePerson(id: $id) {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
displayName
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useGetPersonQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useGetPersonQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useGetPersonQuery` 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 } = useGetPersonQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useGetPersonQuery(baseOptions: Apollo.QueryHookOptions<GetPersonQuery, GetPersonQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<GetPersonQuery, GetPersonQueryVariables>(GetPersonDocument, options);
|
||||||
|
}
|
||||||
|
export function useGetPersonLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetPersonQuery, GetPersonQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<GetPersonQuery, GetPersonQueryVariables>(GetPersonDocument, options);
|
||||||
|
}
|
||||||
|
export type GetPersonQueryHookResult = ReturnType<typeof useGetPersonQuery>;
|
||||||
|
export type GetPersonLazyQueryHookResult = ReturnType<typeof useGetPersonLazyQuery>;
|
||||||
|
export type GetPersonQueryResult = Apollo.QueryResult<GetPersonQuery, GetPersonQueryVariables>;
|
||||||
export const UpdatePeopleDocument = gql`
|
export const UpdatePeopleDocument = gql`
|
||||||
mutation UpdatePeople($id: String, $firstName: String, $lastName: String, $phone: String, $city: String, $companyId: String, $email: String, $createdAt: DateTime) {
|
mutation UpdatePeople($id: String, $firstName: String, $lastName: String, $phone: String, $city: String, $companyId: String, $email: String, $createdAt: DateTime) {
|
||||||
updateOnePerson(
|
updateOnePerson(
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const StyledContainer = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: ${({ theme }) => theme.font.size.sm}px;
|
font-size: ${({ theme }) => theme.font.size.sm};
|
||||||
text-align: center;
|
text-align: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export const StyledDialog = styled(Command.Dialog)`
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
z-index: 1000;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const StyledInput = styled(Command.Input)`
|
export const StyledInput = styled(Command.Input)`
|
||||||
|
|||||||
@ -1,108 +0,0 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
|
||||||
import { GET_COMPANIES } from '@/companies/services';
|
|
||||||
import { GET_PEOPLE } from '@/people/services';
|
|
||||||
import { AutosizeTextInput } from '@/ui/components/inputs/AutosizeTextInput';
|
|
||||||
import { logError } from '@/utils/logs/logError';
|
|
||||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
|
||||||
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
|
|
||||||
import { useCreateCommentMutation } from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
|
|
||||||
|
|
||||||
import { CommentThreadActionBar } from './CommentThreadActionBar';
|
|
||||||
import { CommentThreadItem } from './CommentThreadItem';
|
|
||||||
import { CommentThreadRelationPicker } from './CommentThreadRelationPicker';
|
|
||||||
|
|
||||||
type OwnProps = {
|
|
||||||
commentThread: CommentThreadForDrawer;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
gap: ${({ theme }) => theme.spacing(4)};
|
|
||||||
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledThreadItemListContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
flex-direction: column;
|
|
||||||
gap: ${({ theme }) => theme.spacing(4)};
|
|
||||||
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function CommentThread({ commentThread }: OwnProps) {
|
|
||||||
const [createCommentMutation] = useCreateCommentMutation();
|
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
|
||||||
|
|
||||||
function handleSendComment(commentText: string) {
|
|
||||||
if (!isNonEmptyString(commentText)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefined(currentUser)) {
|
|
||||||
logError(
|
|
||||||
'In handleSendComment, currentUser is not defined, this should not happen.',
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
createCommentMutation({
|
|
||||||
variables: {
|
|
||||||
commentId: v4(),
|
|
||||||
authorId: currentUser.id,
|
|
||||||
commentThreadId: commentThread.id,
|
|
||||||
commentText,
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_COMPANIES) ?? '',
|
|
||||||
getOperationName(GET_PEOPLE) ?? '',
|
|
||||||
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
|
||||||
],
|
|
||||||
onError: (error) => {
|
|
||||||
logError(
|
|
||||||
`In handleSendComment, createCommentMutation onError, error: ${error}`,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer>
|
|
||||||
<StyledThreadItemListContainer>
|
|
||||||
{commentThread.comments?.map((comment, index) => (
|
|
||||||
<CommentThreadItem
|
|
||||||
key={comment.id}
|
|
||||||
comment={comment}
|
|
||||||
actionBar={
|
|
||||||
index === 0 ? (
|
|
||||||
<CommentThreadActionBar commentThreadId={commentThread.id} />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</StyledThreadItemListContainer>
|
|
||||||
<CommentThreadRelationPicker commentThread={commentThread} />
|
|
||||||
<AutosizeTextInput onValidate={handleSendComment} />
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,148 +0,0 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
|
||||||
import { v4 } from 'uuid';
|
|
||||||
|
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
|
||||||
import { commentableEntityArrayState } from '@/comments/states/commentableEntityArrayState';
|
|
||||||
import { createdCommentThreadIdState } from '@/comments/states/createdCommentThreadIdState';
|
|
||||||
import { GET_COMPANIES } from '@/companies/services';
|
|
||||||
import { GET_PEOPLE } from '@/people/services';
|
|
||||||
import { AutosizeTextInput } from '@/ui/components/inputs/AutosizeTextInput';
|
|
||||||
import { useOpenRightDrawer } from '@/ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
|
||||||
import { logError } from '@/utils/logs/logError';
|
|
||||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
|
||||||
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
|
|
||||||
import {
|
|
||||||
useCreateCommentMutation,
|
|
||||||
useCreateCommentThreadWithCommentMutation,
|
|
||||||
useGetCommentThreadQuery,
|
|
||||||
} from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { GET_COMMENT_THREAD } from '../services';
|
|
||||||
|
|
||||||
import { CommentThreadItem } from './CommentThreadItem';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: ${({ theme }) => theme.spacing(4)};
|
|
||||||
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
max-height: calc(100% - 16px);
|
|
||||||
padding: ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledThreadItemListContainer = styled.div`
|
|
||||||
align-items: flex-start;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
flex-direction: column-reverse;
|
|
||||||
gap: ${({ theme }) => theme.spacing(4)};
|
|
||||||
|
|
||||||
justify-content: flex-start;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function CommentThreadCreateMode() {
|
|
||||||
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
|
|
||||||
|
|
||||||
const [createdCommmentThreadId, setCreatedCommentThreadId] = useRecoilState(
|
|
||||||
createdCommentThreadIdState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const openRightDrawer = useOpenRightDrawer();
|
|
||||||
|
|
||||||
const [createCommentMutation] = useCreateCommentMutation();
|
|
||||||
|
|
||||||
const [createCommentThreadWithComment] =
|
|
||||||
useCreateCommentThreadWithCommentMutation();
|
|
||||||
|
|
||||||
const { data } = useGetCommentThreadQuery({
|
|
||||||
variables: {
|
|
||||||
commentThreadId: createdCommmentThreadId ?? '',
|
|
||||||
},
|
|
||||||
skip: !createdCommmentThreadId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const comments = data?.findManyCommentThreads[0]?.comments;
|
|
||||||
|
|
||||||
const displayCommentList = (comments?.length ?? 0) > 0;
|
|
||||||
|
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
|
||||||
|
|
||||||
function handleNewComment(commentText: string) {
|
|
||||||
if (!isNonEmptyString(commentText)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isDefined(currentUser)) {
|
|
||||||
logError(
|
|
||||||
'In handleCreateCommentThread, currentUser is not defined, this should not happen.',
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!createdCommmentThreadId) {
|
|
||||||
createCommentThreadWithComment({
|
|
||||||
variables: {
|
|
||||||
authorId: currentUser.id,
|
|
||||||
commentId: v4(),
|
|
||||||
commentText: commentText,
|
|
||||||
commentThreadId: v4(),
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
commentThreadTargetArray: commentableEntityArray.map(
|
|
||||||
(commentableEntity) => ({
|
|
||||||
commentableId: commentableEntity.id,
|
|
||||||
commentableType: commentableEntity.type,
|
|
||||||
id: v4(),
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
refetchQueries: [
|
|
||||||
getOperationName(GET_COMPANIES) ?? '',
|
|
||||||
getOperationName(GET_PEOPLE) ?? '',
|
|
||||||
getOperationName(GET_COMMENT_THREAD) ?? '',
|
|
||||||
],
|
|
||||||
onCompleted(data) {
|
|
||||||
setCreatedCommentThreadId(data.createOneCommentThread.id);
|
|
||||||
openRightDrawer('comments');
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
createCommentMutation({
|
|
||||||
variables: {
|
|
||||||
commentId: v4(),
|
|
||||||
authorId: currentUser.id,
|
|
||||||
commentThreadId: createdCommmentThreadId,
|
|
||||||
commentText,
|
|
||||||
createdAt: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
refetchQueries: [getOperationName(GET_COMMENT_THREAD) ?? ''],
|
|
||||||
onError: (error) => {
|
|
||||||
logError(
|
|
||||||
`In handleCreateCommentThread, createCommentMutation onError, error: ${error}`,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledContainer>
|
|
||||||
{displayCommentList && (
|
|
||||||
<StyledThreadItemListContainer>
|
|
||||||
{comments?.map((comment) => (
|
|
||||||
<CommentThreadItem key={comment.id} comment={comment} />
|
|
||||||
))}
|
|
||||||
</StyledThreadItemListContainer>
|
|
||||||
)}
|
|
||||||
<AutosizeTextInput minRows={5} onValidate={handleNewComment} />
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
import { useRecoilState } from 'recoil';
|
|
||||||
|
|
||||||
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
|
||||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
|
||||||
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
|
||||||
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
|
||||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
|
||||||
import {
|
|
||||||
SortOrder,
|
|
||||||
useGetCommentThreadsByTargetsQuery,
|
|
||||||
} from '~/generated/graphql';
|
|
||||||
|
|
||||||
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
|
||||||
|
|
||||||
import { CommentThread } from './CommentThread';
|
|
||||||
|
|
||||||
export function RightDrawerComments() {
|
|
||||||
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
|
|
||||||
useHotkeysScopeOnMountOnly({
|
|
||||||
scope: InternalHotkeysScope.RightDrawer,
|
|
||||||
customScopes: { goto: false, 'command-menu': true },
|
|
||||||
});
|
|
||||||
|
|
||||||
const { data: queryResult } = useGetCommentThreadsByTargetsQuery({
|
|
||||||
variables: {
|
|
||||||
commentThreadTargetIds: commentableEntityArray.map(
|
|
||||||
(commentableEntity) => commentableEntity.id,
|
|
||||||
),
|
|
||||||
orderBy: [
|
|
||||||
{
|
|
||||||
createdAt: SortOrder.Desc,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const commentThreads: CommentThreadForDrawer[] =
|
|
||||||
queryResult?.findManyCommentThreads ?? [];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RightDrawerPage>
|
|
||||||
<RightDrawerTopBar title="Comments" />
|
|
||||||
<RightDrawerBody>
|
|
||||||
{commentThreads.map((commentThread) => (
|
|
||||||
<CommentThread key={commentThread.id} commentThread={commentThread} />
|
|
||||||
))}
|
|
||||||
</RightDrawerBody>
|
|
||||||
</RightDrawerPage>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import { BlockNoteEditor } from '@blocknote/core';
|
||||||
|
import { useBlockNote } from '@blocknote/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/comments/services';
|
||||||
|
import { BlockEditor } from '@/ui/components/editor/BlockEditor';
|
||||||
|
import { debounce } from '@/utils/debounce';
|
||||||
|
import {
|
||||||
|
CommentThread,
|
||||||
|
useUpdateCommentThreadBodyMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
const BlockNoteStyledContainer = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
commentThread: Pick<CommentThread, 'id' | 'body'>;
|
||||||
|
onChange?: (commentThreadBody: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CommentThreadBodyEditor({ commentThread, onChange }: OwnProps) {
|
||||||
|
const [updateCommentThreadBodyMutation] =
|
||||||
|
useUpdateCommentThreadBodyMutation();
|
||||||
|
|
||||||
|
const debounceOnChange = useMemo(() => {
|
||||||
|
function onInternalChange(commentThreadBody: string) {
|
||||||
|
onChange?.(commentThreadBody);
|
||||||
|
updateCommentThreadBodyMutation({
|
||||||
|
variables: {
|
||||||
|
commentThreadId: commentThread.id,
|
||||||
|
commentThreadBody: commentThreadBody,
|
||||||
|
},
|
||||||
|
refetchQueries: [
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return debounce(onInternalChange, 200);
|
||||||
|
}, [commentThread, updateCommentThreadBodyMutation, onChange]);
|
||||||
|
|
||||||
|
const editor: BlockNoteEditor | null = useBlockNote({
|
||||||
|
initialContent: commentThread.body
|
||||||
|
? JSON.parse(commentThread.body)
|
||||||
|
: undefined,
|
||||||
|
editorDOMAttributes: { class: 'editor-edit-mode' },
|
||||||
|
onEditorContentChange: (editor) => {
|
||||||
|
debounceOnChange(JSON.stringify(editor.topLevelBlocks) ?? '');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BlockNoteStyledContainer>
|
||||||
|
<BlockEditor editor={editor} />
|
||||||
|
</BlockNoteStyledContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/comments/services';
|
||||||
|
import { CommentForDrawer } from '@/comments/types/CommentForDrawer';
|
||||||
|
import { AutosizeTextInput } from '@/ui/components/inputs/AutosizeTextInput';
|
||||||
|
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
|
||||||
|
import { CommentThread, useCreateCommentMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { CommentThreadItem } from '../comment/CommentThreadItem';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
commentThread: Pick<CommentThread, 'id'> & {
|
||||||
|
comments: Array<CommentForDrawer>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledThreadItemListContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
|
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: ${({ theme }) => theme.spacing(8)};
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(12)};
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCommentActionBar = styled.div`
|
||||||
|
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
display: flex;
|
||||||
|
padding: 16px 24px 16px 48px;
|
||||||
|
width: calc(${({ theme }) => theme.rightDrawerWidth} - 48px - 24px);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function CommentThreadComments({ commentThread }: OwnProps) {
|
||||||
|
const [createCommentMutation] = useCreateCommentMutation();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
|
if (!currentUser) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSendComment(commentText: string) {
|
||||||
|
if (!isNonEmptyString(commentText)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
createCommentMutation({
|
||||||
|
variables: {
|
||||||
|
commentId: v4(),
|
||||||
|
authorId: currentUser?.id ?? '',
|
||||||
|
commentThreadId: commentThread?.id ?? '',
|
||||||
|
commentText: commentText,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? ''],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{commentThread?.comments.length > 0 && (
|
||||||
|
<StyledThreadItemListContainer>
|
||||||
|
{commentThread?.comments?.map((comment, index) => (
|
||||||
|
<CommentThreadItem key={comment.id} comment={comment} />
|
||||||
|
))}
|
||||||
|
</StyledThreadItemListContainer>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<StyledCommentActionBar>
|
||||||
|
{currentUser && <AutosizeTextInput onValidate={handleSendComment} />}
|
||||||
|
</StyledCommentActionBar>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import {
|
import {
|
||||||
autoUpdate,
|
autoUpdate,
|
||||||
@ -8,30 +7,33 @@ import {
|
|||||||
size,
|
size,
|
||||||
useFloating,
|
useFloating,
|
||||||
} from '@floating-ui/react';
|
} from '@floating-ui/react';
|
||||||
import { IconArrowUpRight } from '@tabler/icons-react';
|
|
||||||
|
|
||||||
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange';
|
||||||
|
import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect';
|
||||||
import CompanyChip from '@/companies/components/CompanyChip';
|
import CompanyChip from '@/companies/components/CompanyChip';
|
||||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
import { PersonChip } from '@/people/components/PersonChip';
|
import { PersonChip } from '@/people/components/PersonChip';
|
||||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||||
|
import { MultipleEntitySelect } from '@/relation-picker/components/MultipleEntitySelect';
|
||||||
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
|
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
|
||||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||||
import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/ui/utils/flatMapAndSortEntityForSelectArrayByName';
|
import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/ui/utils/flatMapAndSortEntityForSelectArrayByName';
|
||||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||||
import {
|
import {
|
||||||
CommentableType,
|
CommentableType,
|
||||||
|
CommentThread,
|
||||||
|
CommentThreadTarget,
|
||||||
useSearchCompanyQuery,
|
useSearchCompanyQuery,
|
||||||
useSearchPeopleQuery,
|
useSearchPeopleQuery,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
import { MultipleEntitySelect } from '../../relation-picker/components/MultipleEntitySelect';
|
|
||||||
import { useHandleCheckableCommentThreadTargetChange } from '../hooks/useHandleCheckableCommentThreadTargetChange';
|
|
||||||
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
commentThread: CommentThreadForDrawer;
|
commentThread?: Pick<CommentThread, 'id'> & {
|
||||||
|
commentThreadTargets: Array<
|
||||||
|
Pick<CommentThreadTarget, 'id' | 'commentableId' | 'commentableType'>
|
||||||
|
>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
@ -44,25 +46,6 @@ const StyledContainer = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLabelContainer = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
gap: ${({ theme }) => theme.spacing(2)};
|
|
||||||
|
|
||||||
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
|
||||||
padding-top: ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledRelationLabel = styled.div`
|
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
user-select: none;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledRelationContainer = styled.div`
|
const StyledRelationContainer = styled.div`
|
||||||
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
|
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
|
||||||
--vertical-padding: ${({ theme }) => theme.spacing(1.5)};
|
--vertical-padding: ${({ theme }) => theme.spacing(1.5)};
|
||||||
@ -97,15 +80,12 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
|||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [searchFilter, setSearchFilter] = useState('');
|
const [searchFilter, setSearchFilter] = useState('');
|
||||||
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const peopleIds =
|
const peopleIds =
|
||||||
commentThread.commentThreadTargets
|
commentThread?.commentThreadTargets
|
||||||
?.filter((relation) => relation.commentableType === 'Person')
|
?.filter((relation) => relation.commentableType === 'Person')
|
||||||
.map((relation) => relation.commentableId) ?? [];
|
.map((relation) => relation.commentableId) ?? [];
|
||||||
|
|
||||||
const companyIds =
|
const companyIds =
|
||||||
commentThread.commentThreadTargets
|
commentThread?.commentThreadTargets
|
||||||
?.filter((relation) => relation.commentableType === 'Company')
|
?.filter((relation) => relation.commentableType === 'Company')
|
||||||
.map((relation) => relation.commentableId) ?? [];
|
.map((relation) => relation.commentableId) ?? [];
|
||||||
|
|
||||||
@ -203,10 +183,6 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledLabelContainer>
|
|
||||||
<IconArrowUpRight size={16} color={theme.font.color.tertiary} />
|
|
||||||
<StyledRelationLabel>Relations</StyledRelationLabel>
|
|
||||||
</StyledLabelContainer>
|
|
||||||
<StyledRelationContainer
|
<StyledRelationContainer
|
||||||
ref={refs.setReference}
|
ref={refs.setReference}
|
||||||
onClick={handleRelationContainerClick}
|
onClick={handleRelationContainerClick}
|
||||||
@ -215,11 +191,12 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
|||||||
entity.entityType === CommentableType.Company ? (
|
entity.entityType === CommentableType.Company ? (
|
||||||
<CompanyChip
|
<CompanyChip
|
||||||
key={entity.id}
|
key={entity.id}
|
||||||
|
id={entity.id}
|
||||||
name={entity.name}
|
name={entity.name}
|
||||||
picture={entity.avatarUrl}
|
picture={entity.avatarUrl}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<PersonChip key={entity.id} name={entity.name} />
|
<PersonChip key={entity.id} name={entity.name} id={entity.id} />
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
</StyledRelationContainer>
|
</StyledRelationContainer>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import {
|
||||||
|
DropdownButton,
|
||||||
|
DropdownOptionType,
|
||||||
|
} from '@/ui/components/buttons/DropdownButton';
|
||||||
|
import { IconNotes } from '@/ui/icons/index';
|
||||||
|
|
||||||
|
export function CommentThreadTypeDropdown() {
|
||||||
|
const options: DropdownOptionType[] = [
|
||||||
|
{ label: 'Notes', icon: <IconNotes /> },
|
||||||
|
// { label: 'Call', icon: <IconPhone /> },
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleSelect = (selectedOption: DropdownOptionType) => {
|
||||||
|
// console.log(`You selected: ${selectedOption.label}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return <DropdownButton options={options} onSelection={handleSelect} />;
|
||||||
|
}
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
@ -24,8 +25,10 @@ type Story = StoryObj<typeof CommentThreadRelationPicker>;
|
|||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
render: getRenderWrapperForComponent(
|
render: getRenderWrapperForComponent(
|
||||||
<StyledContainer>
|
<MemoryRouter>
|
||||||
<CommentThreadRelationPicker commentThread={mockedCommentThreads[0]} />
|
<StyledContainer>
|
||||||
</StyledContainer>,
|
<CommentThreadRelationPicker commentThread={mockedCommentThreads[0]} />
|
||||||
|
</StyledContainer>
|
||||||
|
</MemoryRouter>,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
@ -22,7 +22,7 @@ const StyledCommentBody = styled.div`
|
|||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
|
|
||||||
line-height: ${({ theme }) => theme.text.lineHeight};
|
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
|
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
@ -6,8 +6,8 @@ import { CommentForDrawer } from '@/comments/types/CommentForDrawer';
|
|||||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
import { mockedUsersData } from '~/testing/mock-data/users';
|
||||||
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
|
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
|
||||||
|
|
||||||
|
import { CommentThreadActionBar } from '../../right-drawer/CommentThreadActionBar';
|
||||||
import { CommentHeader } from '../CommentHeader';
|
import { CommentHeader } from '../CommentHeader';
|
||||||
import { CommentThreadActionBar } from '../CommentThreadActionBar';
|
|
||||||
|
|
||||||
const meta: Meta<typeof CommentHeader> = {
|
const meta: Meta<typeof CommentHeader> = {
|
||||||
title: 'Modules/Comments/CommentHeader',
|
title: 'Modules/Comments/CommentHeader',
|
||||||
@ -0,0 +1,164 @@
|
|||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/comments/services';
|
||||||
|
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
|
||||||
|
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
|
||||||
|
import { IconArrowUpRight } from '@/ui/icons/index';
|
||||||
|
import { debounce } from '@/utils/debounce';
|
||||||
|
import {
|
||||||
|
useGetCommentThreadQuery,
|
||||||
|
useUpdateCommentThreadTitleMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { CommentThreadBodyEditor } from '../comment-thread/CommentThreadBodyEditor';
|
||||||
|
import { CommentThreadComments } from '../comment-thread/CommentThreadComments';
|
||||||
|
import { CommentThreadRelationPicker } from '../comment-thread/CommentThreadRelationPicker';
|
||||||
|
import { CommentThreadTypeDropdown } from '../comment-thread/CommentThreadTypeDropdown';
|
||||||
|
|
||||||
|
import { CommentThreadActionBar } from './CommentThreadActionBar';
|
||||||
|
|
||||||
|
import '@blocknote/core/style.css';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: ${({ theme }) => theme.spacing(4)};
|
||||||
|
|
||||||
|
justify-content: flex-start;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTopContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 24px 24px 24px 48px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledEditableTitleInput = styled.input`
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xl};
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||||
|
outline: none;
|
||||||
|
width: calc(100% - ${({ theme }) => theme.spacing(2)});
|
||||||
|
:placeholder {
|
||||||
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTopActionsContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
commentThreadId: string;
|
||||||
|
showComment?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function CommentThread({
|
||||||
|
commentThreadId,
|
||||||
|
showComment = true,
|
||||||
|
}: OwnProps) {
|
||||||
|
const { data } = useGetCommentThreadQuery({
|
||||||
|
variables: {
|
||||||
|
commentThreadId: commentThreadId ?? '',
|
||||||
|
},
|
||||||
|
skip: !commentThreadId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [updateCommentThreadTitleMutation] =
|
||||||
|
useUpdateCommentThreadTitleMutation();
|
||||||
|
|
||||||
|
const debounceUpdateTitle = useMemo(() => {
|
||||||
|
function updateTitle(title: string) {
|
||||||
|
updateCommentThreadTitleMutation({
|
||||||
|
variables: {
|
||||||
|
commentThreadId: commentThreadId,
|
||||||
|
commentThreadTitle: title ?? '',
|
||||||
|
},
|
||||||
|
refetchQueries: [
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return debounce(updateTitle, 200);
|
||||||
|
}, [commentThreadId, updateCommentThreadTitleMutation]);
|
||||||
|
|
||||||
|
function updateTitleFromBody(body: string) {
|
||||||
|
const title = JSON.parse(body)[0]?.content[0]?.text;
|
||||||
|
if (!commentThread?.title || commentThread?.title === '') {
|
||||||
|
debounceUpdateTitle(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commentThread = data?.findManyCommentThreads[0];
|
||||||
|
|
||||||
|
if (!commentThread) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainer>
|
||||||
|
<StyledTopContainer>
|
||||||
|
<StyledTopActionsContainer>
|
||||||
|
<CommentThreadTypeDropdown />
|
||||||
|
<CommentThreadActionBar commentThreadId={commentThread?.id ?? ''} />
|
||||||
|
</StyledTopActionsContainer>
|
||||||
|
<StyledEditableTitleInput
|
||||||
|
placeholder="Note title (optional)"
|
||||||
|
onChange={(event) => debounceUpdateTitle(event.target.value)}
|
||||||
|
value={commentThread?.title ?? ''}
|
||||||
|
/>
|
||||||
|
<PropertyBox>
|
||||||
|
<PropertyBoxItem
|
||||||
|
icon={<IconArrowUpRight />}
|
||||||
|
value={
|
||||||
|
<CommentThreadRelationPicker
|
||||||
|
commentThread={{
|
||||||
|
id: commentThread.id,
|
||||||
|
commentThreadTargets:
|
||||||
|
commentThread.commentThreadTargets ?? [],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label="Relations"
|
||||||
|
/>
|
||||||
|
</PropertyBox>
|
||||||
|
</StyledTopContainer>
|
||||||
|
<CommentThreadBodyEditor
|
||||||
|
commentThread={commentThread}
|
||||||
|
onChange={updateTitleFromBody}
|
||||||
|
/>
|
||||||
|
{showComment && (
|
||||||
|
<CommentThreadComments
|
||||||
|
commentThread={{
|
||||||
|
id: commentThread.id,
|
||||||
|
comments: commentThread.comments ?? [],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -3,14 +3,13 @@ import { useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '@/comments/services';
|
||||||
import { GET_COMPANIES } from '@/companies/services';
|
import { GET_COMPANIES } from '@/companies/services';
|
||||||
import { GET_PEOPLE } from '@/people/services';
|
import { GET_PEOPLE } from '@/people/services';
|
||||||
import { IconTrash } from '@/ui/icons';
|
import { IconTrash } from '@/ui/icons';
|
||||||
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '@/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
||||||
import { useDeleteCommentThreadMutation } from '~/generated/graphql';
|
import { useDeleteCommentThreadMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { commentableEntityArrayState } from '@/comments/states/commentableEntityArrayState';
|
||||||
|
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||||
|
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||||
|
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||||
|
|
||||||
|
import { Timeline } from '../timeline/Timeline';
|
||||||
|
|
||||||
|
export function RightDrawerTimeline() {
|
||||||
|
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
|
||||||
|
|
||||||
|
useHotkeysScopeOnMountOnly({
|
||||||
|
scope: InternalHotkeysScope.RightDrawer,
|
||||||
|
customScopes: { goto: false, 'command-menu': true },
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RightDrawerPage>
|
||||||
|
<RightDrawerTopBar title="Timeline" />
|
||||||
|
<RightDrawerBody>
|
||||||
|
{commentableEntityArray.map((commentableEntity) => (
|
||||||
|
<Timeline
|
||||||
|
key={commentableEntity.id}
|
||||||
|
entity={{
|
||||||
|
id: commentableEntity?.id ?? '',
|
||||||
|
type: commentableEntity.type,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</RightDrawerBody>
|
||||||
|
</RightDrawerPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState';
|
||||||
|
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||||
|
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||||
|
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||||
|
|
||||||
|
import { CommentThread } from '../CommentThread';
|
||||||
|
|
||||||
|
export function RightDrawerCreateCommentThread() {
|
||||||
|
const commentThreadId = useRecoilValue(viewableCommentThreadIdState);
|
||||||
|
|
||||||
|
useHotkeysScopeOnMountOnly({
|
||||||
|
scope: InternalHotkeysScope.RightDrawer,
|
||||||
|
customScopes: { goto: false, 'command-menu': true },
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RightDrawerPage>
|
||||||
|
<RightDrawerTopBar
|
||||||
|
title="New note"
|
||||||
|
onSave={() => {
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<RightDrawerBody>
|
||||||
|
{commentThreadId && (
|
||||||
|
<CommentThread
|
||||||
|
commentThreadId={commentThreadId}
|
||||||
|
showComment={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</RightDrawerBody>
|
||||||
|
</RightDrawerPage>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,21 +1,25 @@
|
|||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
import { viewableCommentThreadIdState } from '@/comments/states/viewableCommentThreadIdState';
|
||||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
|
||||||
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
|
||||||
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
|
||||||
|
|
||||||
import { CommentThreadCreateMode } from './CommentThreadCreateMode';
|
import { CommentThread } from '../CommentThread';
|
||||||
|
|
||||||
export function RightDrawerCreateCommentThread() {
|
export function RightDrawerEditCommentThread() {
|
||||||
useHotkeysScopeOnMountOnly({
|
useHotkeysScopeOnMountOnly({
|
||||||
scope: InternalHotkeysScope.RightDrawer,
|
scope: InternalHotkeysScope.RightDrawer,
|
||||||
customScopes: { goto: false, 'command-menu': true },
|
customScopes: { goto: false, 'command-menu': true },
|
||||||
});
|
});
|
||||||
|
const commentThreadId = useRecoilValue(viewableCommentThreadIdState);
|
||||||
return (
|
return (
|
||||||
<RightDrawerPage>
|
<RightDrawerPage>
|
||||||
<RightDrawerTopBar title="New comment" />
|
<RightDrawerTopBar title="" />
|
||||||
<RightDrawerBody>
|
<RightDrawerBody>
|
||||||
<CommentThreadCreateMode />
|
{commentThreadId && <CommentThread commentThreadId={commentThreadId} />}
|
||||||
</RightDrawerBody>
|
</RightDrawerBody>
|
||||||
</RightDrawerPage>
|
</RightDrawerPage>
|
||||||
);
|
);
|
||||||
@ -41,9 +41,8 @@ const StyledChip = styled.div`
|
|||||||
const StyledCount = styled.div`
|
const StyledCount = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: 12px;
|
font-size: ${({ theme }) => theme.font.size.sm};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
font-weight: 500;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
288
front/src/modules/comments/components/timeline/Timeline.tsx
Normal file
288
front/src/modules/comments/components/timeline/Timeline.tsx
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tooltip } from 'react-tooltip';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { useOpenCommentThreadRightDrawer } from '@/comments/hooks/useOpenCommentThreadRightDrawer';
|
||||||
|
import { useOpenCreateCommentThreadDrawer } from '@/comments/hooks/useOpenCreateCommentThreadDrawer';
|
||||||
|
import { CommentableEntity } from '@/comments/types/CommentableEntity';
|
||||||
|
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
|
||||||
|
import { TableActionBarButtonToggleComments } from '@/ui/components/table/action-bar/TableActionBarButtonOpenComments';
|
||||||
|
import { IconCirclePlus, IconNotes } from '@/ui/icons/index';
|
||||||
|
import {
|
||||||
|
beautifyExactDate,
|
||||||
|
beautifyPastDateRelativeToNow,
|
||||||
|
} from '@/utils/datetime/date-utils';
|
||||||
|
import {
|
||||||
|
SortOrder,
|
||||||
|
useGetCommentThreadsByTargetsQuery,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
|
const StyledMainContainer = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTimelineContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 12px 16px 12px 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTimelineEmptyContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledEmptyTimelineTitle = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xxl};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledEmptyTimelineSubTitle = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.extraLight};
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xxl};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.md};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTimelineItemContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
display: flex;
|
||||||
|
height: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledItemTitleContainer = styled.div`
|
||||||
|
align-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px 8px;
|
||||||
|
height: 20px;
|
||||||
|
span {
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledItemTitleDate = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledVerticalLineContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledVerticalLine = styled.div`
|
||||||
|
align-self: stretch;
|
||||||
|
background: ${({ theme }) => theme.border.color.light};
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 2px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCardContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 4px 0px 20px 0px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCard = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
max-width: 400px;
|
||||||
|
padding: 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCardTitle = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCardContent = styled.div`
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
|
||||||
|
-webkit-line-clamp: 3;
|
||||||
|
align-self: stretch;
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTooltip = styled(Tooltip)`
|
||||||
|
background-color: ${({ theme }) => theme.background.primary};
|
||||||
|
|
||||||
|
box-shadow: 0px 2px 4px 3px
|
||||||
|
${({ theme }) => theme.background.transparent.light};
|
||||||
|
|
||||||
|
box-shadow: 2px 4px 16px 6px
|
||||||
|
${({ theme }) => theme.background.transparent.light};
|
||||||
|
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
|
||||||
|
opacity: 1;
|
||||||
|
padding: 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTopActionBar = styled.div`
|
||||||
|
align-items: flex-start;
|
||||||
|
align-self: stretch;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
|
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
border-top-right-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
left: 0px;
|
||||||
|
padding: 12px 16px 12px 16px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function Timeline({ entity }: { entity: CommentableEntity }) {
|
||||||
|
const { data: queryResult } = useGetCommentThreadsByTargetsQuery({
|
||||||
|
variables: {
|
||||||
|
commentThreadTargetIds: [entity.id],
|
||||||
|
orderBy: [
|
||||||
|
{
|
||||||
|
createdAt: SortOrder.Desc,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const openCommentThreadRightDrawer = useOpenCommentThreadRightDrawer();
|
||||||
|
|
||||||
|
const openCreateCommandThread = useOpenCreateCommentThreadDrawer();
|
||||||
|
|
||||||
|
const commentThreads: CommentThreadForDrawer[] =
|
||||||
|
queryResult?.findManyCommentThreads ?? [];
|
||||||
|
|
||||||
|
if (!commentThreads.length) {
|
||||||
|
return (
|
||||||
|
<StyledTimelineEmptyContainer>
|
||||||
|
<StyledEmptyTimelineTitle>No activity yet</StyledEmptyTimelineTitle>
|
||||||
|
<StyledEmptyTimelineSubTitle>Create one:</StyledEmptyTimelineSubTitle>
|
||||||
|
<TableActionBarButtonToggleComments
|
||||||
|
onClick={() => openCreateCommandThread(entity)}
|
||||||
|
/>
|
||||||
|
</StyledTimelineEmptyContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledMainContainer>
|
||||||
|
<StyledTopActionBar>
|
||||||
|
<StyledTimelineItemContainer>
|
||||||
|
<StyledIconContainer>
|
||||||
|
<IconCirclePlus />
|
||||||
|
</StyledIconContainer>
|
||||||
|
|
||||||
|
<TableActionBarButtonToggleComments
|
||||||
|
onClick={() => openCreateCommandThread(entity)}
|
||||||
|
/>
|
||||||
|
</StyledTimelineItemContainer>
|
||||||
|
</StyledTopActionBar>
|
||||||
|
<StyledTimelineContainer>
|
||||||
|
{commentThreads.map((commentThread) => {
|
||||||
|
const beautifiedCreatedAt = beautifyPastDateRelativeToNow(
|
||||||
|
commentThread.createdAt,
|
||||||
|
);
|
||||||
|
const exactCreatedAt = beautifyExactDate(commentThread.createdAt);
|
||||||
|
const body = JSON.parse(commentThread.body ?? '{}')[0]?.content[0]
|
||||||
|
?.text;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={commentThread.id}>
|
||||||
|
<StyledTimelineItemContainer>
|
||||||
|
<StyledIconContainer>
|
||||||
|
<IconNotes />
|
||||||
|
</StyledIconContainer>
|
||||||
|
<StyledItemTitleContainer>
|
||||||
|
<span>
|
||||||
|
{commentThread.author.firstName}{' '}
|
||||||
|
{commentThread.author.lastName}
|
||||||
|
</span>
|
||||||
|
created a note
|
||||||
|
</StyledItemTitleContainer>
|
||||||
|
<StyledItemTitleDate id={`id-${commentThread.id}`}>
|
||||||
|
{beautifiedCreatedAt} ago
|
||||||
|
</StyledItemTitleDate>
|
||||||
|
<StyledTooltip
|
||||||
|
anchorSelect={`#id-${commentThread.id}`}
|
||||||
|
content={exactCreatedAt}
|
||||||
|
clickable
|
||||||
|
noArrow
|
||||||
|
/>
|
||||||
|
</StyledTimelineItemContainer>
|
||||||
|
<StyledTimelineItemContainer>
|
||||||
|
<StyledVerticalLineContainer>
|
||||||
|
<StyledVerticalLine></StyledVerticalLine>
|
||||||
|
</StyledVerticalLineContainer>
|
||||||
|
<StyledCardContainer>
|
||||||
|
<StyledCard
|
||||||
|
onClick={() =>
|
||||||
|
openCommentThreadRightDrawer(commentThread.id)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<StyledCardTitle>
|
||||||
|
{commentThread.title ? commentThread.title : '(No title)'}
|
||||||
|
</StyledCardTitle>
|
||||||
|
<StyledCardContent>
|
||||||
|
{body ? body : '(No content)'}
|
||||||
|
</StyledCardContent>
|
||||||
|
</StyledCard>
|
||||||
|
</StyledCardContainer>
|
||||||
|
</StyledTimelineItemContainer>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</StyledTimelineContainer>
|
||||||
|
</StyledMainContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -4,18 +4,23 @@ import { v4 } from 'uuid';
|
|||||||
import { GET_COMPANIES } from '@/companies/services';
|
import { GET_COMPANIES } from '@/companies/services';
|
||||||
import { GET_PEOPLE } from '@/people/services';
|
import { GET_PEOPLE } from '@/people/services';
|
||||||
import {
|
import {
|
||||||
|
CommentThread,
|
||||||
|
CommentThreadTarget,
|
||||||
useAddCommentThreadTargetOnCommentThreadMutation,
|
useAddCommentThreadTargetOnCommentThreadMutation,
|
||||||
useRemoveCommentThreadTargetOnCommentThreadMutation,
|
useRemoveCommentThreadTargetOnCommentThreadMutation,
|
||||||
} from '~/generated/graphql';
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
|
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
|
||||||
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
|
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
|
||||||
import { CommentThreadForDrawer } from '../types/CommentThreadForDrawer';
|
|
||||||
|
|
||||||
export function useHandleCheckableCommentThreadTargetChange({
|
export function useHandleCheckableCommentThreadTargetChange({
|
||||||
commentThread,
|
commentThread,
|
||||||
}: {
|
}: {
|
||||||
commentThread: CommentThreadForDrawer;
|
commentThread?: Pick<CommentThread, 'id'> & {
|
||||||
|
commentThreadTargets: Array<
|
||||||
|
Pick<CommentThreadTarget, 'id' | 'commentableId'>
|
||||||
|
>;
|
||||||
|
};
|
||||||
}) {
|
}) {
|
||||||
const [addCommentThreadTargetOnCommentThread] =
|
const [addCommentThreadTargetOnCommentThread] =
|
||||||
useAddCommentThreadTargetOnCommentThreadMutation({
|
useAddCommentThreadTargetOnCommentThreadMutation({
|
||||||
@ -39,6 +44,9 @@ export function useHandleCheckableCommentThreadTargetChange({
|
|||||||
newCheckedValue: boolean,
|
newCheckedValue: boolean,
|
||||||
entity: CommentableEntityForSelect,
|
entity: CommentableEntityForSelect,
|
||||||
) {
|
) {
|
||||||
|
if (!commentThread) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (newCheckedValue) {
|
if (newCheckedValue) {
|
||||||
addCommentThreadTargetOnCommentThread({
|
addCommentThreadTargetOnCommentThread({
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
|
|
||||||
|
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
||||||
|
import { viewableCommentThreadIdState } from '../states/viewableCommentThreadIdState';
|
||||||
|
|
||||||
|
export function useOpenCommentThreadRightDrawer() {
|
||||||
|
const openRightDrawer = useOpenRightDrawer();
|
||||||
|
const [, setViewableCommentThreadId] = useRecoilState(
|
||||||
|
viewableCommentThreadIdState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return function openCommentThreadRightDrawer(commentThreadId: string) {
|
||||||
|
setViewableCommentThreadId(commentThreadId);
|
||||||
|
openRightDrawer(RightDrawerPages.EditCommentThread);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,38 +1,73 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities/graphql/getFromAST';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { GET_COMPANIES } from '@/companies/services';
|
||||||
|
import { GET_PEOPLE } from '@/people/services';
|
||||||
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
|
import { selectedRowIdsState } from '@/ui/tables/states/selectedRowIdsState';
|
||||||
import { CommentableType } from '~/generated/graphql';
|
import {
|
||||||
|
CommentableType,
|
||||||
|
useCreateCommentThreadMutation,
|
||||||
|
} from '~/generated/graphql';
|
||||||
|
|
||||||
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
||||||
|
import {
|
||||||
|
GET_COMMENT_THREAD,
|
||||||
|
GET_COMMENT_THREADS_BY_TARGETS,
|
||||||
|
} from '../services';
|
||||||
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
||||||
import { createdCommentThreadIdState } from '../states/createdCommentThreadIdState';
|
import { viewableCommentThreadIdState } from '../states/viewableCommentThreadIdState';
|
||||||
import { CommentableEntity } from '../types/CommentableEntity';
|
import { CommentableEntity } from '../types/CommentableEntity';
|
||||||
|
|
||||||
export function useOpenCreateCommentThreadDrawerForSelectedRowIds() {
|
export function useOpenCreateCommentThreadDrawerForSelectedRowIds() {
|
||||||
const openRightDrawer = useOpenRightDrawer();
|
const openRightDrawer = useOpenRightDrawer();
|
||||||
|
const [createCommentThreadMutation] = useCreateCommentThreadMutation();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
const [, setViewableCommentThreadId] = useRecoilState(
|
||||||
|
viewableCommentThreadIdState,
|
||||||
|
);
|
||||||
|
|
||||||
const [, setCommentableEntityArray] = useRecoilState(
|
const [, setCommentableEntityArray] = useRecoilState(
|
||||||
commentableEntityArrayState,
|
commentableEntityArrayState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [, setCreatedCommentThreadId] = useRecoilState(
|
const selectedEntityIds = useRecoilValue(selectedRowIdsState);
|
||||||
createdCommentThreadIdState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const selectedPeopleIds = useRecoilValue(selectedRowIdsState);
|
|
||||||
|
|
||||||
return function openCreateCommentDrawerForSelectedRowIds(
|
return function openCreateCommentDrawerForSelectedRowIds(
|
||||||
entityType: CommentableType,
|
entityType: CommentableType,
|
||||||
) {
|
) {
|
||||||
const commentableEntityArray: CommentableEntity[] = selectedPeopleIds.map(
|
const commentableEntityArray: CommentableEntity[] = selectedEntityIds.map(
|
||||||
(id) => ({
|
(id) => ({
|
||||||
type: entityType,
|
type: entityType,
|
||||||
id,
|
id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
setCreatedCommentThreadId(null);
|
createCommentThreadMutation({
|
||||||
setCommentableEntityArray(commentableEntityArray);
|
variables: {
|
||||||
openRightDrawer('create-comment-thread');
|
authorId: currentUser?.id ?? '',
|
||||||
|
commentThreadId: v4(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
commentThreadTargetArray: commentableEntityArray.map((entity) => ({
|
||||||
|
commentableId: entity.id,
|
||||||
|
commentableType: entity.type,
|
||||||
|
id: v4(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
refetchQueries: [
|
||||||
|
getOperationName(GET_COMPANIES) ?? '',
|
||||||
|
getOperationName(GET_PEOPLE) ?? '',
|
||||||
|
getOperationName(GET_COMMENT_THREAD) ?? '',
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
],
|
||||||
|
onCompleted(data) {
|
||||||
|
setViewableCommentThreadId(data.createOneCommentThread.id);
|
||||||
|
setCommentableEntityArray(commentableEntityArray);
|
||||||
|
openRightDrawer(RightDrawerPages.CreateCommentThread);
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,60 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
|
import { GET_COMPANIES } from '@/companies/services';
|
||||||
|
import { GET_PEOPLE } from '@/people/services';
|
||||||
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
|
import { useCreateCommentThreadMutation } from '~/generated/graphql';
|
||||||
|
|
||||||
|
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
||||||
|
import {
|
||||||
|
GET_COMMENT_THREAD,
|
||||||
|
GET_COMMENT_THREADS_BY_TARGETS,
|
||||||
|
} from '../services';
|
||||||
|
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
||||||
|
import { viewableCommentThreadIdState } from '../states/viewableCommentThreadIdState';
|
||||||
|
import { CommentableEntity } from '../types/CommentableEntity';
|
||||||
|
|
||||||
|
export function useOpenCreateCommentThreadDrawer() {
|
||||||
|
const openRightDrawer = useOpenRightDrawer();
|
||||||
|
const [createCommentThreadMutation] = useCreateCommentThreadMutation();
|
||||||
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|
||||||
|
const [, setCommentableEntityArray] = useRecoilState(
|
||||||
|
commentableEntityArrayState,
|
||||||
|
);
|
||||||
|
const [, setViewableCommentThreadId] = useRecoilState(
|
||||||
|
viewableCommentThreadIdState,
|
||||||
|
);
|
||||||
|
|
||||||
|
return function openCreateCommentThreadDrawer(entity: CommentableEntity) {
|
||||||
|
createCommentThreadMutation({
|
||||||
|
variables: {
|
||||||
|
authorId: currentUser?.id ?? '',
|
||||||
|
commentThreadId: v4(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
commentThreadTargetArray: [
|
||||||
|
{
|
||||||
|
commentableId: entity.id,
|
||||||
|
commentableType: entity.type,
|
||||||
|
id: v4(),
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
refetchQueries: [
|
||||||
|
getOperationName(GET_COMPANIES) ?? '',
|
||||||
|
getOperationName(GET_PEOPLE) ?? '',
|
||||||
|
getOperationName(GET_COMMENT_THREAD) ?? '',
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
],
|
||||||
|
onCompleted(data) {
|
||||||
|
setViewableCommentThreadId(data.createOneCommentThread.id);
|
||||||
|
setCommentableEntityArray([entity]);
|
||||||
|
openRightDrawer(RightDrawerPages.CreateCommentThread);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,19 +1,21 @@
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { RightDrawerPages } from '@/ui/layout/right-drawer/types/RightDrawerPages';
|
||||||
|
|
||||||
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
|
||||||
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
|
||||||
import { CommentableEntity } from '../types/CommentableEntity';
|
import { CommentableEntity } from '../types/CommentableEntity';
|
||||||
|
|
||||||
export function useOpenCommentRightDrawer() {
|
export function useOpenTimelineRightDrawer() {
|
||||||
const openRightDrawer = useOpenRightDrawer();
|
const openRightDrawer = useOpenRightDrawer();
|
||||||
const [, setCommentableEntityArray] = useRecoilState(
|
const [, setCommentableEntityArray] = useRecoilState(
|
||||||
commentableEntityArrayState,
|
commentableEntityArrayState,
|
||||||
);
|
);
|
||||||
|
|
||||||
return function openCommentRightDrawer(
|
return function openTimelineRightDrawer(
|
||||||
commentableEntityArray: CommentableEntity[],
|
commentableEntityArray: CommentableEntity[],
|
||||||
) {
|
) {
|
||||||
setCommentableEntityArray(commentableEntityArray);
|
setCommentableEntityArray(commentableEntityArray);
|
||||||
openRightDrawer('comments');
|
openRightDrawer(RightDrawerPages.Timeline);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -33,12 +33,12 @@ export const CREATE_COMMENT = gql`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const CREATE_COMMENT_THREAD_WITH_COMMENT = gql`
|
export const CREATE_COMMENT_THREAD_WITH_COMMENT = gql`
|
||||||
mutation CreateCommentThreadWithComment(
|
mutation CreateCommentThread(
|
||||||
$commentThreadId: String!
|
$commentThreadId: String!
|
||||||
$commentText: String!
|
$body: String
|
||||||
|
$title: String
|
||||||
$authorId: String!
|
$authorId: String!
|
||||||
$createdAt: DateTime!
|
$createdAt: DateTime!
|
||||||
$commentId: String!
|
|
||||||
$commentThreadTargetArray: [CommentThreadTargetCreateManyCommentThreadInput!]!
|
$commentThreadTargetArray: [CommentThreadTargetCreateManyCommentThreadInput!]!
|
||||||
) {
|
) {
|
||||||
createOneCommentThread(
|
createOneCommentThread(
|
||||||
@ -46,16 +46,9 @@ export const CREATE_COMMENT_THREAD_WITH_COMMENT = gql`
|
|||||||
id: $commentThreadId
|
id: $commentThreadId
|
||||||
createdAt: $createdAt
|
createdAt: $createdAt
|
||||||
updatedAt: $createdAt
|
updatedAt: $createdAt
|
||||||
comments: {
|
author: { connect: { id: $authorId } }
|
||||||
createMany: {
|
body: $body
|
||||||
data: {
|
title: $title
|
||||||
authorId: $authorId
|
|
||||||
id: $commentId
|
|
||||||
createdAt: $createdAt
|
|
||||||
body: $commentText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commentThreadTargets: {
|
commentThreadTargets: {
|
||||||
createMany: { data: $commentThreadTargetArray, skipDuplicates: true }
|
createMany: { data: $commentThreadTargetArray, skipDuplicates: true }
|
||||||
}
|
}
|
||||||
@ -64,6 +57,7 @@ export const CREATE_COMMENT_THREAD_WITH_COMMENT = gql`
|
|||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
|
authorId
|
||||||
commentThreadTargets {
|
commentThreadTargets {
|
||||||
id
|
id
|
||||||
createdAt
|
createdAt
|
||||||
|
|||||||
@ -14,6 +14,14 @@ export const GET_COMMENT_THREADS_BY_TARGETS = gql`
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
createdAt
|
||||||
|
title
|
||||||
|
body
|
||||||
|
author {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
comments {
|
comments {
|
||||||
id
|
id
|
||||||
body
|
body
|
||||||
@ -40,6 +48,14 @@ export const GET_COMMENT_THREAD = gql`
|
|||||||
query GetCommentThread($commentThreadId: String!) {
|
query GetCommentThread($commentThreadId: String!) {
|
||||||
findManyCommentThreads(where: { id: { equals: $commentThreadId } }) {
|
findManyCommentThreads(where: { id: { equals: $commentThreadId } }) {
|
||||||
id
|
id
|
||||||
|
createdAt
|
||||||
|
body
|
||||||
|
title
|
||||||
|
author {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
comments {
|
comments {
|
||||||
id
|
id
|
||||||
body
|
body
|
||||||
@ -54,6 +70,7 @@ export const GET_COMMENT_THREAD = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
commentThreadTargets {
|
commentThreadTargets {
|
||||||
|
id
|
||||||
commentableId
|
commentableId
|
||||||
commentableType
|
commentableType
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,3 +68,33 @@ export const DELETE_COMMENT_THREAD = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const UPDATE_COMMENT_THREAD_TITLE = gql`
|
||||||
|
mutation UpdateCommentThreadTitle(
|
||||||
|
$commentThreadId: String!
|
||||||
|
$commentThreadTitle: String
|
||||||
|
) {
|
||||||
|
updateOneCommentThread(
|
||||||
|
where: { id: $commentThreadId }
|
||||||
|
data: { title: { set: $commentThreadTitle } }
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const UPDATE_COMMENT_THREAD_BODY = gql`
|
||||||
|
mutation UpdateCommentThreadBody(
|
||||||
|
$commentThreadId: String!
|
||||||
|
$commentThreadBody: String
|
||||||
|
) {
|
||||||
|
updateOneCommentThread(
|
||||||
|
where: { id: $commentThreadId }
|
||||||
|
data: { body: { set: $commentThreadBody } }
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
import { atom } from 'recoil';
|
|
||||||
|
|
||||||
export const createdCommentThreadIdState = atom<string | null>({
|
|
||||||
key: 'comments/created-comment-thread-id',
|
|
||||||
default: null,
|
|
||||||
});
|
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
|
export const viewableCommentThreadIdState = atom<string | null>({
|
||||||
|
key: 'comments/viewable-comment-thread-id',
|
||||||
|
default: null,
|
||||||
|
});
|
||||||
@ -1,23 +1,27 @@
|
|||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Theme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { Avatar } from '@/users/components/Avatar';
|
import { Avatar } from '@/users/components/Avatar';
|
||||||
|
|
||||||
export type CompanyChipPropsType = {
|
export type CompanyChipPropsType = {
|
||||||
|
id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
picture?: string;
|
picture?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.span`
|
const baseStyle = ({ theme }: { theme: Theme }) => `
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ theme }) => theme.background.tertiary};
|
background-color: ${theme.background.tertiary};
|
||||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
border-radius: ${theme.spacing(1)};
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${theme.font.color.primary};
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${theme.spacing(1)};
|
||||||
height: calc(20px - 2 * ${({ theme }) => theme.spacing(1)});
|
height: calc(20px - 2 * ${theme.spacing(1)});
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding: ${theme.spacing(1)};
|
||||||
|
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
text-decoration: none;
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
@ -38,9 +42,19 @@ const StyledName = styled.span`
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function CompanyChip({ name, picture }: CompanyChipPropsType) {
|
const StyledContainerLink = styled(Link)`
|
||||||
|
${baseStyle}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledContainerNoLink = styled.div`
|
||||||
|
${baseStyle}
|
||||||
|
`;
|
||||||
|
|
||||||
|
function CompanyChip({ id, name, picture }: CompanyChipPropsType) {
|
||||||
|
const ContainerComponent = id ? StyledContainerLink : StyledContainerNoLink;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer data-testid="company-chip">
|
<ContainerComponent data-testid="company-chip" to={`/companies/${id}`}>
|
||||||
{picture && (
|
{picture && (
|
||||||
<Avatar
|
<Avatar
|
||||||
avatarUrl={picture?.toString()}
|
avatarUrl={picture?.toString()}
|
||||||
@ -50,7 +64,7 @@ function CompanyChip({ name, picture }: CompanyChipPropsType) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<StyledName>{name}</StyledName>
|
<StyledName>{name}</StyledName>
|
||||||
</StyledContainer>
|
</ContainerComponent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
import { CellCommentChip } from '@/comments/components/table/CellCommentChip';
|
||||||
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
import { useOpenTimelineRightDrawer } from '@/comments/hooks/useOpenTimelineRightDrawer';
|
||||||
import { EditableCellChip } from '@/ui/components/editable-cell/types/EditableChip';
|
import { EditableCellChip } from '@/ui/components/editable-cell/types/EditableChip';
|
||||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||||
import {
|
import {
|
||||||
@ -13,12 +13,12 @@ import CompanyChip from './CompanyChip';
|
|||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
company: Pick<
|
company: Pick<
|
||||||
GetCompaniesQuery['companies'][0],
|
GetCompaniesQuery['companies'][0],
|
||||||
'id' | 'name' | 'domainName' | '_commentCount' | 'accountOwner'
|
'id' | 'name' | 'domainName' | '_commentThreadCount' | 'accountOwner'
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function CompanyEditableNameChipCell({ company }: OwnProps) {
|
export function CompanyEditableNameChipCell({ company }: OwnProps) {
|
||||||
const openCommentRightDrawer = useOpenCommentRightDrawer();
|
const openCommentRightDrawer = useOpenTimelineRightDrawer();
|
||||||
const [updateCompany] = useUpdateCompanyMutation();
|
const [updateCompany] = useUpdateCompanyMutation();
|
||||||
|
|
||||||
function handleCommentClick(event: React.MouseEvent<HTMLDivElement>) {
|
function handleCommentClick(event: React.MouseEvent<HTMLDivElement>) {
|
||||||
@ -38,6 +38,7 @@ export function CompanyEditableNameChipCell({ company }: OwnProps) {
|
|||||||
value={company.name || ''}
|
value={company.name || ''}
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
picture={getLogoUrlFromDomainName(company.domainName)}
|
picture={getLogoUrlFromDomainName(company.domainName)}
|
||||||
|
id={company.id}
|
||||||
changeHandler={(value: string) => {
|
changeHandler={(value: string) => {
|
||||||
updateCompany({
|
updateCompany({
|
||||||
variables: {
|
variables: {
|
||||||
@ -50,7 +51,7 @@ export function CompanyEditableNameChipCell({ company }: OwnProps) {
|
|||||||
ChipComponent={CompanyChip}
|
ChipComponent={CompanyChip}
|
||||||
rightEndContents={[
|
rightEndContents={[
|
||||||
<CellCommentChip
|
<CellCommentChip
|
||||||
count={company._commentCount ?? 0}
|
count={company._commentThreadCount ?? 0}
|
||||||
onClick={handleCommentClick}
|
onClick={handleCommentClick}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
|
|||||||
@ -33,8 +33,8 @@ export const SmallName: Story = {
|
|||||||
render: getRenderWrapperForComponent(
|
render: getRenderWrapperForComponent(
|
||||||
<TestCellContainer>
|
<TestCellContainer>
|
||||||
<CompanyChip
|
<CompanyChip
|
||||||
name="Instragram"
|
name="Airbnb"
|
||||||
picture="https://api.faviconkit.com/instagram.com/144"
|
picture="https://api.faviconkit.com/airbnb.com/144"
|
||||||
/>
|
/>
|
||||||
</TestCellContainer>,
|
</TestCellContainer>,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './select';
|
export * from './select';
|
||||||
|
export * from './show';
|
||||||
export * from './update';
|
export * from './update';
|
||||||
|
|||||||
@ -22,7 +22,7 @@ export const GET_COMPANIES = gql`
|
|||||||
createdAt
|
createdAt
|
||||||
address
|
address
|
||||||
employees
|
employees
|
||||||
_commentCount
|
_commentThreadCount
|
||||||
accountOwner {
|
accountOwner {
|
||||||
id
|
id
|
||||||
email
|
email
|
||||||
|
|||||||
26
front/src/modules/companies/services/show.ts
Normal file
26
front/src/modules/companies/services/show.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
import { useGetCompanyQuery } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const GET_COMPANY = gql`
|
||||||
|
query GetCompany($id: String!) {
|
||||||
|
findUniqueCompany(id: $id) {
|
||||||
|
id
|
||||||
|
domainName
|
||||||
|
name
|
||||||
|
createdAt
|
||||||
|
address
|
||||||
|
employees
|
||||||
|
_commentThreadCount
|
||||||
|
accountOwner {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function useCompanyQuery(id: string) {
|
||||||
|
return useGetCompanyQuery({ variables: { id } });
|
||||||
|
}
|
||||||
@ -16,4 +16,5 @@ export enum InternalHotkeysScope {
|
|||||||
PasswordLogin = 'password-login',
|
PasswordLogin = 'password-login',
|
||||||
AuthIndex = 'auth-index',
|
AuthIndex = 'auth-index',
|
||||||
CreateProfile = 'create-profile',
|
CreateProfile = 'create-profile',
|
||||||
|
ShowPage = 'show-page',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
import { CellCommentChip } from '@/comments/components/table/CellCommentChip';
|
||||||
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
import { useOpenTimelineRightDrawer } from '@/comments/hooks/useOpenTimelineRightDrawer';
|
||||||
import { EditableCellDoubleText } from '@/ui/components/editable-cell/types/EditableCellDoubleText';
|
import { EditableCellDoubleText } from '@/ui/components/editable-cell/types/EditableCellDoubleText';
|
||||||
import { CommentableType, Person } from '~/generated/graphql';
|
import { CommentableType, Person } from '~/generated/graphql';
|
||||||
|
|
||||||
import { PersonChip } from './PersonChip';
|
import { PersonChip } from './PersonChip';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
person: Pick<Person, 'id' | 'firstName' | 'lastName' | '_commentCount'>;
|
person: Pick<Person, 'id' | 'firstName' | 'lastName' | '_commentThreadCount'>;
|
||||||
onChange: (firstName: string, lastName: string) => void;
|
onChange: (firstName: string, lastName: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ const RightContainer = styled.div`
|
|||||||
export function EditablePeopleFullName({ person, onChange }: OwnProps) {
|
export function EditablePeopleFullName({ person, onChange }: OwnProps) {
|
||||||
const [firstNameValue, setFirstNameValue] = useState(person.firstName ?? '');
|
const [firstNameValue, setFirstNameValue] = useState(person.firstName ?? '');
|
||||||
const [lastNameValue, setLastNameValue] = useState(person.lastName ?? '');
|
const [lastNameValue, setLastNameValue] = useState(person.lastName ?? '');
|
||||||
const openCommentRightDrawer = useOpenCommentRightDrawer();
|
const openCommentRightDrawer = useOpenTimelineRightDrawer();
|
||||||
|
|
||||||
function handleDoubleTextChange(
|
function handleDoubleTextChange(
|
||||||
firstValue: string,
|
firstValue: string,
|
||||||
@ -60,10 +60,13 @@ export function EditablePeopleFullName({ person, onChange }: OwnProps) {
|
|||||||
onChange={handleDoubleTextChange}
|
onChange={handleDoubleTextChange}
|
||||||
nonEditModeContent={
|
nonEditModeContent={
|
||||||
<NoEditModeContainer>
|
<NoEditModeContainer>
|
||||||
<PersonChip name={person.firstName + ' ' + person.lastName} />
|
<PersonChip
|
||||||
|
name={person.firstName + ' ' + person.lastName}
|
||||||
|
id={person.id}
|
||||||
|
/>
|
||||||
<RightContainer>
|
<RightContainer>
|
||||||
<CellCommentChip
|
<CellCommentChip
|
||||||
count={person._commentCount ?? 0}
|
count={person._commentThreadCount ?? 0}
|
||||||
onClick={handleCommentClick}
|
onClick={handleCommentClick}
|
||||||
/>
|
/>
|
||||||
</RightContainer>
|
</RightContainer>
|
||||||
|
|||||||
@ -30,6 +30,7 @@ export function PeopleCompanyCell({ people }: OwnProps) {
|
|||||||
}
|
}
|
||||||
nonEditModeContent={
|
nonEditModeContent={
|
||||||
<CompanyChip
|
<CompanyChip
|
||||||
|
id={people.company?.id ?? ''}
|
||||||
name={people.company?.name ?? ''}
|
name={people.company?.name ?? ''}
|
||||||
picture={getLogoUrlFromDomainName(people.company?.domainName)}
|
picture={getLogoUrlFromDomainName(people.company?.domainName)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,54 +1,63 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Theme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import PersonPlaceholder from './person-placeholder.png';
|
import PersonPlaceholder from './person-placeholder.png';
|
||||||
|
|
||||||
export type PersonChipPropsType = {
|
export type PersonChipPropsType = {
|
||||||
|
id?: string;
|
||||||
name: string;
|
name: string;
|
||||||
picture?: string;
|
picture?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledContainer = styled.span`
|
const baseStyle = ({ theme }: { theme: Theme }) => `
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: ${({ theme }) => theme.background.tertiary};
|
background-color: ${theme.background.tertiary};
|
||||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
border-radius: ${theme.spacing(1)};
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${theme.font.color.primary};
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
gap: ${({ theme }) => theme.spacing(1)};
|
gap: ${theme.spacing(1)};
|
||||||
height: 12px;
|
height: 12px;
|
||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: ${({ theme }) => theme.spacing(1)};
|
padding: ${theme.spacing(1)};
|
||||||
|
text-decoration: none;
|
||||||
:hover {
|
:hover {
|
||||||
filter: brightness(95%);
|
filter: brightness(95%);
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const StyledContainerLink = styled(Link)`
|
||||||
|
${baseStyle}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledContainerNoLink = styled.div`
|
||||||
|
${baseStyle}
|
||||||
|
`;
|
||||||
|
|
||||||
const StyledName = styled.span`
|
const StyledName = styled.span`
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function PersonChip({ name, picture }: PersonChipPropsType) {
|
export function PersonChip({ id, name, picture }: PersonChipPropsType) {
|
||||||
|
const ContainerComponent = id ? StyledContainerLink : StyledContainerNoLink;
|
||||||
return (
|
return (
|
||||||
<StyledContainer data-testid="person-chip">
|
<ContainerComponent data-testid="person-chip" to={`/person/${id}`}>
|
||||||
<img
|
<img
|
||||||
data-testid="person-chip-image"
|
data-testid="person-chip-image"
|
||||||
src={picture ? picture.toString() : PersonPlaceholder.toString()}
|
src={picture ? picture.toString() : PersonPlaceholder.toString()}
|
||||||
alt="person"
|
alt="person"
|
||||||
/>
|
/>
|
||||||
<StyledName>{name}</StyledName>
|
<StyledName>{name}</StyledName>
|
||||||
</StyledContainer>
|
</ContainerComponent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './select';
|
export * from './select';
|
||||||
|
export * from './show';
|
||||||
export * from './update';
|
export * from './update';
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export const GET_PEOPLE = gql`
|
|||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
createdAt
|
createdAt
|
||||||
_commentCount
|
_commentThreadCount
|
||||||
company {
|
company {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
|||||||
19
front/src/modules/people/services/show.ts
Normal file
19
front/src/modules/people/services/show.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { gql } from '@apollo/client';
|
||||||
|
|
||||||
|
import { useGetPersonQuery } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export const GET_PERSON = gql`
|
||||||
|
query GetPerson($id: String!) {
|
||||||
|
findUniquePerson(id: $id) {
|
||||||
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
displayName
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function usePersonQuery(id: string) {
|
||||||
|
return useGetPersonQuery({ variables: { id } });
|
||||||
|
}
|
||||||
94
front/src/modules/ui/components/buttons/DropdownButton.tsx
Normal file
94
front/src/modules/ui/components/buttons/DropdownButton.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { IconChevronDown } from '@/ui/icons/index';
|
||||||
|
|
||||||
|
type ButtonProps = React.ComponentProps<'button'>;
|
||||||
|
|
||||||
|
export type DropdownOptionType = {
|
||||||
|
label: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
options: DropdownOptionType[];
|
||||||
|
onSelection: (value: DropdownOptionType) => void;
|
||||||
|
} & ButtonProps;
|
||||||
|
|
||||||
|
const StyledButton = styled.button<ButtonProps>`
|
||||||
|
align-items: center;
|
||||||
|
background: ${({ theme }) => theme.background.tertiary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: 4px;
|
||||||
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
|
display: flex;
|
||||||
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
|
gap: 8px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
|
padding: 3px 8px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 14px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DropdownContainer = styled.div`
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DropdownMenu = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: -2px;
|
||||||
|
position: absolute;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function DropdownButton({
|
||||||
|
options,
|
||||||
|
onSelection,
|
||||||
|
...buttonProps
|
||||||
|
}: Props) {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [selectedOption, setSelectedOption] = useState(options[0]);
|
||||||
|
|
||||||
|
if (!options.length) {
|
||||||
|
throw new Error('You must provide at least one option.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelect =
|
||||||
|
(option: DropdownOptionType) =>
|
||||||
|
(event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
onSelection(option);
|
||||||
|
setSelectedOption(option);
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownContainer>
|
||||||
|
<StyledButton onClick={() => setIsOpen(!isOpen)} {...buttonProps}>
|
||||||
|
{selectedOption.icon}
|
||||||
|
{selectedOption.label}
|
||||||
|
{options.length > 1 && <IconChevronDown />}
|
||||||
|
</StyledButton>
|
||||||
|
{isOpen && (
|
||||||
|
<DropdownMenu>
|
||||||
|
{options
|
||||||
|
.filter((option) => option.label !== selectedOption.label)
|
||||||
|
.map((option, index) => (
|
||||||
|
<StyledButton key={index} onClick={handleSelect(option)}>
|
||||||
|
{option.icon}
|
||||||
|
{option.label}
|
||||||
|
</StyledButton>
|
||||||
|
))}
|
||||||
|
</DropdownMenu>
|
||||||
|
)}
|
||||||
|
</DropdownContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -6,17 +6,19 @@ import { textInputStyle } from '@/ui/themes/effects';
|
|||||||
import { EditableCell } from '../EditableCell';
|
import { EditableCell } from '../EditableCell';
|
||||||
|
|
||||||
export type EditableChipProps = {
|
export type EditableChipProps = {
|
||||||
|
id: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
value: string;
|
value: string;
|
||||||
picture: string;
|
picture: string;
|
||||||
changeHandler: (updated: string) => void;
|
changeHandler: (updated: string) => void;
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
ChipComponent: ComponentType<{
|
ChipComponent: ComponentType<{
|
||||||
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
picture: string;
|
picture: string;
|
||||||
isOverlapped?: boolean;
|
isOverlapped?: boolean;
|
||||||
}>;
|
}>;
|
||||||
commentCount?: number;
|
commentThreadCount?: number;
|
||||||
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||||
rightEndContents?: ReactNode[];
|
rightEndContents?: ReactNode[];
|
||||||
};
|
};
|
||||||
@ -41,6 +43,7 @@ const RightContainer = styled.div`
|
|||||||
|
|
||||||
// TODO: move right end content in EditableCell
|
// TODO: move right end content in EditableCell
|
||||||
export function EditableCellChip({
|
export function EditableCellChip({
|
||||||
|
id,
|
||||||
value,
|
value,
|
||||||
placeholder,
|
placeholder,
|
||||||
changeHandler,
|
changeHandler,
|
||||||
@ -75,7 +78,7 @@ export function EditableCellChip({
|
|||||||
}
|
}
|
||||||
nonEditModeContent={
|
nonEditModeContent={
|
||||||
<NoEditModeContainer>
|
<NoEditModeContainer>
|
||||||
<ChipComponent name={inputValue} picture={picture} />
|
<ChipComponent id={id} name={inputValue} picture={picture} />
|
||||||
<RightContainer>
|
<RightContainer>
|
||||||
{rightEndContents &&
|
{rightEndContents &&
|
||||||
rightEndContents.length > 0 &&
|
rightEndContents.length > 0 &&
|
||||||
|
|||||||
28
front/src/modules/ui/components/editor/BlockEditor.tsx
Normal file
28
front/src/modules/ui/components/editor/BlockEditor.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { BlockNoteEditor } from '@blocknote/core';
|
||||||
|
import { BlockNoteView } from '@blocknote/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
interface BlockEditorProps {
|
||||||
|
editor: BlockNoteEditor | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledEditor = styled.div`
|
||||||
|
min-height: 200px;
|
||||||
|
width: 100%;
|
||||||
|
& .editor-create-mode,
|
||||||
|
.editor-edit-mode {
|
||||||
|
background: ${({ theme }) => theme.background.primary};
|
||||||
|
}
|
||||||
|
& .editor-create-mode [class^='_inlineContent']:before {
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
font-style: normal !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function BlockEditor({ editor }: BlockEditorProps) {
|
||||||
|
return (
|
||||||
|
<StyledEditor>
|
||||||
|
<BlockNoteView editor={editor} />
|
||||||
|
</StyledEditor>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -22,7 +22,7 @@ const StyledContainer = styled.div`
|
|||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
border: none;
|
border: none;
|
||||||
display: block;
|
display: block;
|
||||||
font-weight: 400;
|
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||||
}
|
}
|
||||||
|
|
||||||
& .react-datepicker-popper {
|
& .react-datepicker-popper {
|
||||||
|
|||||||
@ -27,8 +27,8 @@ const StyledTextArea = styled(TextareaAutosize)`
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 13px;
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
font-weight: 400;
|
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@ -42,7 +42,7 @@ const StyledTextArea = styled(TextareaAutosize)`
|
|||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: ${({ theme }) => theme.font.color.light};
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
font-weight: 400;
|
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export function AutosizeTextInput({
|
|||||||
<>
|
<>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledTextArea
|
<StyledTextArea
|
||||||
placeholder={placeholder || 'Write something...'}
|
placeholder={placeholder || 'Write a comment'}
|
||||||
maxRows={MAX_ROWS}
|
maxRows={MAX_ROWS}
|
||||||
minRows={computedMinRows}
|
minRows={computedMinRows}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
|
|||||||
21
front/src/modules/ui/components/property-box/PropertyBox.tsx
Normal file
21
front/src/modules/ui/components/property-box/PropertyBox.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledPropertyBoxContainer = styled.div`
|
||||||
|
align-self: stretch;
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
interface PropertyBoxProps {
|
||||||
|
children: JSX.Element;
|
||||||
|
extraPadding?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PropertyBox({ children }: PropertyBoxProps) {
|
||||||
|
return <StyledPropertyBoxContainer>{children}</StyledPropertyBoxContainer>;
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
const StyledPropertyBoxItem = styled.div`
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 16px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledValueContainer = styled.div`
|
||||||
|
align-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledLabelAndIconContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
display: flex;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function PropertyBoxItem({
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
}: {
|
||||||
|
icon: ReactNode;
|
||||||
|
label?: string;
|
||||||
|
value: ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<StyledPropertyBoxItem>
|
||||||
|
<StyledLabelAndIconContainer>
|
||||||
|
<StyledIconContainer>{icon}</StyledIconContainer>
|
||||||
|
{label}
|
||||||
|
</StyledLabelAndIconContainer>
|
||||||
|
<StyledValueContainer>{value}</StyledValueContainer>
|
||||||
|
</StyledPropertyBoxItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ const StyledMainSectionTitle = styled.h2`
|
|||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
font-size: ${({ theme }) => theme.font.size.xl};
|
font-size: ${({ theme }) => theme.font.size.xl};
|
||||||
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
line-height: 1.5;
|
line-height: ${({ theme }) => theme.text.lineHeight.lg};
|
||||||
margin: 0;
|
margin: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const StyledTitle = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
height: ${({ theme }) => theme.spacing(8)};
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -32,7 +32,7 @@ const StyledButton = styled.div<StyledButtonProps>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledButtonLabel = styled.div`
|
const StyledButtonLabel = styled.div`
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IconComment } from '@/ui/icons/index';
|
import { IconNotes } from '@/ui/icons/index';
|
||||||
|
|
||||||
import { EntityTableActionBarButton } from './EntityTableActionBarButton';
|
import { EntityTableActionBarButton } from './EntityTableActionBarButton';
|
||||||
|
|
||||||
@ -9,8 +9,8 @@ type OwnProps = {
|
|||||||
export function TableActionBarButtonToggleComments({ onClick }: OwnProps) {
|
export function TableActionBarButtonToggleComments({ onClick }: OwnProps) {
|
||||||
return (
|
return (
|
||||||
<EntityTableActionBarButton
|
<EntityTableActionBarButton
|
||||||
label="Comment"
|
label="Notes"
|
||||||
icon={<IconComment size={16} />}
|
icon={<IconNotes size={16} />}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -179,7 +179,7 @@ function DropdownButton({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const dropdownRef = useRef(null);
|
const dropdownRef = useRef(null);
|
||||||
useOutsideAlerter(dropdownRef, onOutsideClick);
|
useOutsideAlerter({ ref: dropdownRef, callback: onOutsideClick });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledDropdownButtonContainer>
|
<StyledDropdownButtonContainer>
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const StyledCancelButton = styled.button`
|
|||||||
border: none;
|
border: none;
|
||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: ${({ theme }) => theme.spacing(2)};
|
margin-right: ${({ theme }) => theme.spacing(2)};
|
||||||
padding: ${(props) => {
|
padding: ${(props) => {
|
||||||
|
|||||||
@ -45,7 +45,7 @@ const StyledDelete = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledLabelKey = styled.div`
|
const StyledLabelKey = styled.div`
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function SortOrFilterChip({
|
function SortOrFilterChip({
|
||||||
|
|||||||
@ -27,7 +27,7 @@ const StyledTableHeader = styled.div`
|
|||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
height: 40px;
|
height: 40px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding-left: ${({ theme }) => theme.spacing(3)};
|
padding-left: ${({ theme }) => theme.spacing(3)};
|
||||||
@ -49,7 +49,7 @@ const StyledViewSection = styled.div`
|
|||||||
|
|
||||||
const StyledFilters = styled.div`
|
const StyledFilters = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
font-weight: 400;
|
font-weight: ${({ theme }) => theme.font.weight.regular};
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const onOutsideClick = jest.fn();
|
|||||||
|
|
||||||
function TestComponent() {
|
function TestComponent() {
|
||||||
const buttonRef = useRef(null);
|
const buttonRef = useRef(null);
|
||||||
useOutsideAlerter(buttonRef, onOutsideClick);
|
useOutsideAlerter({ ref: buttonRef, callback: onOutsideClick });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -1,21 +1,52 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
declare type CallbackType = () => void;
|
export enum OutsideClickAlerterMode {
|
||||||
|
absolute = 'absolute',
|
||||||
|
dom = 'dom',
|
||||||
|
}
|
||||||
|
|
||||||
export function useOutsideAlerter(
|
type OwnProps = {
|
||||||
ref: React.RefObject<HTMLInputElement>,
|
ref: React.RefObject<HTMLInputElement>;
|
||||||
callback: CallbackType,
|
callback: () => void;
|
||||||
) {
|
mode?: OutsideClickAlerterMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useOutsideAlerter({
|
||||||
|
ref,
|
||||||
|
mode = OutsideClickAlerterMode.dom,
|
||||||
|
callback,
|
||||||
|
}: OwnProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleClickOutside(event: Event) {
|
function handleClickOutside(event: MouseEvent) {
|
||||||
const target = event.target as HTMLButtonElement;
|
const target = event.target as HTMLButtonElement;
|
||||||
if (ref.current && !ref.current.contains(target)) {
|
|
||||||
|
if (!ref.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
mode === OutsideClickAlerterMode.dom &&
|
||||||
|
!ref.current.contains(target)
|
||||||
|
) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode === OutsideClickAlerterMode.absolute) {
|
||||||
|
const { x, y, width, height } = ref.current.getBoundingClientRect();
|
||||||
|
const { clientX, clientY } = event;
|
||||||
|
if (
|
||||||
|
clientX < x ||
|
||||||
|
clientX > x + width ||
|
||||||
|
clientY < y ||
|
||||||
|
clientY > y + height
|
||||||
|
) {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
document.addEventListener('mousedown', handleClickOutside);
|
document.addEventListener('mousedown', handleClickOutside);
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('mousedown', handleClickOutside);
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
};
|
};
|
||||||
}, [ref, callback]);
|
}, [ref, callback, mode]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,3 +30,6 @@ export { IconArrowUpRight } from '@tabler/icons-react';
|
|||||||
export { IconBrandGoogle } from '@tabler/icons-react';
|
export { IconBrandGoogle } from '@tabler/icons-react';
|
||||||
export { IconUpload } from '@tabler/icons-react';
|
export { IconUpload } from '@tabler/icons-react';
|
||||||
export { IconFileUpload } from '@tabler/icons-react';
|
export { IconFileUpload } from '@tabler/icons-react';
|
||||||
|
export { IconChevronsRight } from '@tabler/icons-react';
|
||||||
|
export { IconNotes } from '@tabler/icons-react';
|
||||||
|
export { IconCirclePlus } from '@tabler/icons-react';
|
||||||
|
|||||||
@ -10,7 +10,7 @@ type OwnProps = {
|
|||||||
topMargin?: number;
|
topMargin?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MainContainer = styled.div<{ topMargin: number }>`
|
const StyledMainContainer = styled.div<{ topMargin: number }>`
|
||||||
background: ${({ theme }) => theme.background.noisy};
|
background: ${({ theme }) => theme.background.noisy};
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
@ -27,27 +27,21 @@ type LeftContainerProps = {
|
|||||||
isRightDrawerOpen?: boolean;
|
isRightDrawerOpen?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LeftContainer = styled.div<LeftContainerProps>`
|
const StyledLeftContainer = styled.div<LeftContainerProps>`
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: calc(
|
width: 100%;
|
||||||
100% -
|
|
||||||
${(props) =>
|
|
||||||
props.isRightDrawerOpen
|
|
||||||
? `${props.theme.rightDrawerWidth} - ${props.theme.spacing(2)}`
|
|
||||||
: '0px'}
|
|
||||||
);
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function ContentContainer({ children, topMargin }: OwnProps) {
|
export function ContentContainer({ children, topMargin }: OwnProps) {
|
||||||
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainContainer topMargin={topMargin ?? 0}>
|
<StyledMainContainer topMargin={topMargin ?? 0}>
|
||||||
<LeftContainer isRightDrawerOpen={isRightDrawerOpen}>
|
<StyledLeftContainer isRightDrawerOpen={isRightDrawerOpen}>
|
||||||
<Panel>{children}</Panel>
|
<Panel>{children}</Panel>
|
||||||
</LeftContainer>
|
</StyledLeftContainer>
|
||||||
<RightDrawer />
|
<RightDrawer />
|
||||||
</MainContainer>
|
</StyledMainContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const StyledTitle = styled.div`
|
|||||||
color: ${({ theme }) => theme.font.color.light};
|
color: ${({ theme }) => theme.font.color.light};
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: ${({ theme }) => theme.font.size.xs};
|
font-size: ${({ theme }) => theme.font.size.xs};
|
||||||
font-weight: 600;
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
padding-bottom: ${({ theme }) => theme.spacing(2)};
|
||||||
padding-left: ${({ theme }) => theme.spacing(1)};
|
padding-left: ${({ theme }) => theme.spacing(1)};
|
||||||
padding-top: ${({ theme }) => theme.spacing(8)};
|
padding-top: ${({ theme }) => theme.spacing(8)};
|
||||||
|
|||||||
@ -42,7 +42,7 @@ const StyledName = styled.div`
|
|||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-size: ${({ theme }) => theme.font.size.md};
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
margin-left: ${({ theme }) => theme.spacing(2)};
|
margin-left: ${({ theme }) => theme.spacing(2)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,61 @@
|
|||||||
|
import { useRef } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import {
|
||||||
|
OutsideClickAlerterMode,
|
||||||
|
useOutsideAlerter,
|
||||||
|
} from '@/ui/hooks/useOutsideAlerter';
|
||||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
import { isDefined } from '@/utils/type-guards/isDefined';
|
||||||
|
|
||||||
import { Panel } from '../../Panel';
|
|
||||||
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
||||||
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
||||||
|
|
||||||
import { RightDrawerRouter } from './RightDrawerRouter';
|
import { RightDrawerRouter } from './RightDrawerRouter';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
background: ${({ theme }) => theme.background.primary};
|
||||||
|
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: width 0.5s;
|
||||||
|
width: ${({ theme }) => theme.rightDrawerWidth};
|
||||||
|
z-index: 2;
|
||||||
|
`;
|
||||||
|
|
||||||
const StyledRightDrawer = styled.div`
|
const StyledRightDrawer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: ${({ theme }) => theme.rightDrawerWidth};
|
width: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function RightDrawer() {
|
export function RightDrawer() {
|
||||||
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
const [isRightDrawerOpen, setIsRightDrawerOpen] = useRecoilState(
|
||||||
|
isRightDrawerOpenState,
|
||||||
|
);
|
||||||
|
|
||||||
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||||
|
|
||||||
|
const rightDrawerRef = useRef(null);
|
||||||
|
useOutsideAlerter({
|
||||||
|
ref: rightDrawerRef,
|
||||||
|
callback: () => setIsRightDrawerOpen(false),
|
||||||
|
mode: OutsideClickAlerterMode.absolute,
|
||||||
|
});
|
||||||
if (!isRightDrawerOpen || !isDefined(rightDrawerPage)) {
|
if (!isRightDrawerOpen || !isDefined(rightDrawerPage)) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledRightDrawer>
|
<>
|
||||||
<Panel>
|
<StyledContainer>
|
||||||
<RightDrawerRouter />
|
<StyledRightDrawer ref={rightDrawerRef}>
|
||||||
</Panel>
|
<RightDrawerRouter />
|
||||||
</StyledRightDrawer>
|
</StyledRightDrawer>
|
||||||
|
</StyledContainer>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,5 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
export const RightDrawerBody = styled.div`
|
export const RightDrawerBody = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
height: calc(100vh - ${({ theme }) => theme.spacing(10)});
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { RightDrawerComments } from '@/comments/components/RightDrawerComments';
|
import { RightDrawerCreateCommentThread } from '@/comments/components/right-drawer/create/RightDrawerCreateCommentThread';
|
||||||
import { RightDrawerCreateCommentThread } from '@/comments/components/RightDrawerCreateCommentThread';
|
import { RightDrawerEditCommentThread } from '@/comments/components/right-drawer/edit/RightDrawerEditCommentThread';
|
||||||
|
import { RightDrawerTimeline } from '@/comments/components/right-drawer/RightDrawerTimeline';
|
||||||
import { isDefined } from '@/utils/type-guards/isDefined';
|
import { isDefined } from '@/utils/type-guards/isDefined';
|
||||||
|
|
||||||
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
||||||
|
import { RightDrawerPages } from '../types/RightDrawerPages';
|
||||||
|
|
||||||
export function RightDrawerRouter() {
|
export function RightDrawerRouter() {
|
||||||
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||||
@ -13,11 +15,14 @@ export function RightDrawerRouter() {
|
|||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rightDrawerPage === 'comments' ? (
|
switch (rightDrawerPage) {
|
||||||
<RightDrawerComments />
|
case RightDrawerPages.Timeline:
|
||||||
) : rightDrawerPage === 'create-comment-thread' ? (
|
return <RightDrawerTimeline />;
|
||||||
<RightDrawerCreateCommentThread />
|
case RightDrawerPages.CreateCommentThread:
|
||||||
) : (
|
return <RightDrawerCreateCommentThread />;
|
||||||
<></>
|
case RightDrawerPages.EditCommentThread:
|
||||||
);
|
return <RightDrawerEditCommentThread />;
|
||||||
|
default:
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { Button } from '@/ui/components/buttons/Button';
|
||||||
|
|
||||||
import { RightDrawerTopBarCloseButton } from './RightDrawerTopBarCloseButton';
|
import { RightDrawerTopBarCloseButton } from './RightDrawerTopBarCloseButton';
|
||||||
|
|
||||||
const StyledRightDrawerTopBar = styled.div`
|
const StyledRightDrawerTopBar = styled.div`
|
||||||
@ -8,7 +10,7 @@ const StyledRightDrawerTopBar = styled.div`
|
|||||||
color: ${({ theme }) => theme.font.color.secondary};
|
color: ${({ theme }) => theme.font.color.secondary};
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
font-size: 13px;
|
font-size: ${({ theme }) => theme.font.size.md};
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
@ -17,19 +19,24 @@ const StyledRightDrawerTopBar = styled.div`
|
|||||||
|
|
||||||
const StyledTopBarTitle = styled.div`
|
const StyledTopBarTitle = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: 500;
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||||
margin-right: ${({ theme }) => theme.spacing(1)};
|
margin-right: ${({ theme }) => theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function RightDrawerTopBar({
|
type OwnProps = {
|
||||||
title,
|
|
||||||
}: {
|
|
||||||
title: string | null | undefined;
|
title: string | null | undefined;
|
||||||
}) {
|
onSave?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function RightDrawerTopBar({ title, onSave }: OwnProps) {
|
||||||
|
function handleOnClick() {
|
||||||
|
onSave?.();
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<StyledRightDrawerTopBar>
|
<StyledRightDrawerTopBar>
|
||||||
<StyledTopBarTitle>{title}</StyledTopBarTitle>
|
|
||||||
<RightDrawerTopBarCloseButton />
|
<RightDrawerTopBarCloseButton />
|
||||||
|
<StyledTopBarTitle>{title}</StyledTopBarTitle>
|
||||||
|
{onSave && <Button title="Save" onClick={handleOnClick} />}
|
||||||
</StyledRightDrawerTopBar>
|
</StyledRightDrawerTopBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { IconPlus } from '@/ui/icons/index';
|
import { IconChevronsRight } from '@/ui/icons/index';
|
||||||
|
|
||||||
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
||||||
|
|
||||||
@ -24,7 +24,6 @@ const StyledButton = styled.button`
|
|||||||
}
|
}
|
||||||
svg {
|
svg {
|
||||||
color: ${({ theme }) => theme.font.color.tertiary};
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
transform: rotate(45deg);
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -37,7 +36,7 @@ export function RightDrawerTopBarCloseButton() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledButton onClick={handleButtonClick}>
|
<StyledButton onClick={handleButtonClick}>
|
||||||
<IconPlus size={16} />
|
<IconChevronsRight size={16} />
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,13 +2,13 @@ import { useRecoilState } from 'recoil';
|
|||||||
|
|
||||||
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
||||||
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
||||||
import { RightDrawerPage } from '../types/RightDrawerPage';
|
import { RightDrawerPages } from '../types/RightDrawerPages';
|
||||||
|
|
||||||
export function useOpenRightDrawer() {
|
export function useOpenRightDrawer() {
|
||||||
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||||
const [, setRightDrawerPage] = useRecoilState(rightDrawerPageState);
|
const [, setRightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||||
|
|
||||||
return function openRightDrawer(rightDrawerPage: RightDrawerPage) {
|
return function openRightDrawer(rightDrawerPage: RightDrawerPages) {
|
||||||
setRightDrawerPage(rightDrawerPage);
|
setRightDrawerPage(rightDrawerPage);
|
||||||
setIsRightDrawerOpen(true);
|
setIsRightDrawerOpen(true);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { atom } from 'recoil';
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
import { RightDrawerPage } from '../types/RightDrawerPage';
|
import { RightDrawerPages } from '../types/RightDrawerPages';
|
||||||
|
|
||||||
export const rightDrawerPageState = atom<RightDrawerPage | null>({
|
export const rightDrawerPageState = atom<RightDrawerPages | null>({
|
||||||
key: 'ui/layout/right-drawer-page',
|
key: 'ui/layout/right-drawer-page',
|
||||||
default: null,
|
default: null,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
export type RightDrawerPage = 'comments' | 'create-comment-thread';
|
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
export enum RightDrawerPages {
|
||||||
|
Timeline = 'timeline',
|
||||||
|
CreateCommentThread = 'create-comment-thread',
|
||||||
|
EditCommentThread = 'edit-comment-thread',
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
import { Tooltip } from 'react-tooltip';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { v4 as uuidV4 } from 'uuid';
|
||||||
|
|
||||||
|
import { Avatar } from '@/users/components/Avatar';
|
||||||
|
import {
|
||||||
|
beautifyExactDate,
|
||||||
|
beautifyPastDateRelativeToNow,
|
||||||
|
} from '@/utils/datetime/date-utils';
|
||||||
|
|
||||||
|
const StyledShowPageSummaryCard = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: ${({ theme }) => theme.spacing(3)};
|
||||||
|
justify-content: center;
|
||||||
|
padding: ${({ theme }) => theme.spacing(6)} ${({ theme }) => theme.spacing(3)}
|
||||||
|
${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(3)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledInfoContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledDate = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.tertiary};
|
||||||
|
cursor: pointer;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTitle = styled.div`
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
font-size: ${({ theme }) => theme.font.size.xl};
|
||||||
|
font-weight: ${({ theme }) => theme.font.weight.semiBold};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTooltip = styled(Tooltip)`
|
||||||
|
background-color: ${({ theme }) => theme.background.primary};
|
||||||
|
box-shadow: ${({ theme }) => theme.boxShadow.light};
|
||||||
|
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
|
||||||
|
padding: ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function ShowPageSummaryCard({
|
||||||
|
logoOrAvatar,
|
||||||
|
title,
|
||||||
|
date,
|
||||||
|
}: {
|
||||||
|
logoOrAvatar?: string;
|
||||||
|
title: string;
|
||||||
|
date: string;
|
||||||
|
}) {
|
||||||
|
const beautifiedCreatedAt =
|
||||||
|
date !== '' ? beautifyPastDateRelativeToNow(date) : '';
|
||||||
|
const exactCreatedAt = date !== '' ? beautifyExactDate(date) : '';
|
||||||
|
const theme = useTheme();
|
||||||
|
const dateElementId = `date-id-${uuidV4()}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledShowPageSummaryCard>
|
||||||
|
<Avatar
|
||||||
|
avatarUrl={logoOrAvatar}
|
||||||
|
size={theme.icon.size.xl}
|
||||||
|
placeholder={title}
|
||||||
|
/>
|
||||||
|
<StyledInfoContainer>
|
||||||
|
<StyledTitle>{title}</StyledTitle>
|
||||||
|
<StyledDate id={dateElementId}>
|
||||||
|
Added {beautifiedCreatedAt} ago
|
||||||
|
</StyledDate>
|
||||||
|
<StyledTooltip
|
||||||
|
anchorSelect={`#${dateElementId}`}
|
||||||
|
content={exactCreatedAt}
|
||||||
|
clickable
|
||||||
|
noArrow
|
||||||
|
place="right"
|
||||||
|
/>
|
||||||
|
</StyledInfoContainer>
|
||||||
|
</StyledShowPageSummaryCard>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const ShowPageLeftContainer = styled.div`
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border-radius: 8px;
|
||||||
|
border-right: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
padding: 0px ${({ theme }) => theme.spacing(3)};
|
||||||
|
width: 320px;
|
||||||
|
`;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const ShowPageRightContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex: 1 0 0;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
`;
|
||||||
@ -3,6 +3,7 @@ export const icon = {
|
|||||||
sm: 14,
|
sm: 14,
|
||||||
md: 16,
|
md: 16,
|
||||||
lg: 20,
|
lg: 20,
|
||||||
|
xl: 40,
|
||||||
},
|
},
|
||||||
stroke: {
|
stroke: {
|
||||||
sm: 1.6,
|
sm: 1.6,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ const common = {
|
|||||||
horizontalCellMargin: '8px',
|
horizontalCellMargin: '8px',
|
||||||
checkboxColumnWidth: '32px',
|
checkboxColumnWidth: '32px',
|
||||||
},
|
},
|
||||||
rightDrawerWidth: '300px',
|
rightDrawerWidth: '500px',
|
||||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||||
lastLayerZIndex: 2147483647,
|
lastLayerZIndex: 2147483647,
|
||||||
};
|
};
|
||||||
@ -32,6 +32,7 @@ export const lightTheme = {
|
|||||||
selectedCardHover: color.blue20,
|
selectedCardHover: color.blue20,
|
||||||
selectedCard: color.blue10,
|
selectedCard: color.blue10,
|
||||||
font: fontLight,
|
font: fontLight,
|
||||||
|
name: 'light',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export type ThemeType = typeof lightTheme;
|
export type ThemeType = typeof lightTheme;
|
||||||
@ -45,6 +46,7 @@ export const darkTheme: ThemeType = {
|
|||||||
selectedCardHover: color.blue70,
|
selectedCardHover: color.blue70,
|
||||||
selectedCard: color.blue80,
|
selectedCard: color.blue80,
|
||||||
font: fontDark,
|
font: fontDark,
|
||||||
|
name: 'dark',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -17,8 +17,10 @@ export const StyledAvatar = styled.div<Omit<OwnProps, 'placeholder'>>`
|
|||||||
!isNonEmptyString(props.avatarUrl)
|
!isNonEmptyString(props.avatarUrl)
|
||||||
? props.theme.background.tertiary
|
? props.theme.background.tertiary
|
||||||
: 'none'};
|
: 'none'};
|
||||||
background-image: url(${(props) =>
|
${(props) =>
|
||||||
isNonEmptyString(props.avatarUrl) ? props.avatarUrl : 'none'});
|
isNonEmptyString(props.avatarUrl)
|
||||||
|
? `background-image: url(${props.avatarUrl});`
|
||||||
|
: ''}
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
border-radius: ${(props) => (props.type === 'rounded' ? '50%' : '2px')};
|
border-radius: ${(props) => (props.type === 'rounded' ? '50%' : '2px')};
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { getOperationName } from '@apollo/client/utilities';
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState } from 'recoil';
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { isMockModeState } from '@/auth/states/isMockModeState';
|
|
||||||
import { GET_COMPANIES } from '@/companies/services';
|
import { GET_COMPANIES } from '@/companies/services';
|
||||||
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
@ -28,17 +26,10 @@ const StyledTableContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export function Companies() {
|
export function Companies() {
|
||||||
const [isMockMode] = useRecoilState(isMockModeState);
|
useHotkeysScopeOnMountOnly({
|
||||||
|
scope: InternalHotkeysScope.Table,
|
||||||
const hotkeysEnabled = !isMockMode;
|
customScopes: { 'command-menu': true, goto: true },
|
||||||
|
});
|
||||||
useHotkeysScopeOnMountOnly(
|
|
||||||
{
|
|
||||||
scope: InternalHotkeysScope.Table,
|
|
||||||
customScopes: { 'command-menu': true, goto: true },
|
|
||||||
},
|
|
||||||
hotkeysEnabled,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [insertCompany] = useInsertCompanyMutation();
|
const [insertCompany] = useInsertCompanyMutation();
|
||||||
|
|
||||||
|
|||||||
75
front/src/pages/companies/CompanyShow.tsx
Normal file
75
front/src/pages/companies/CompanyShow.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
|
import { Timeline } from '@/comments/components/timeline/Timeline';
|
||||||
|
import { useCompanyQuery } from '@/companies/services';
|
||||||
|
import { useHotkeysScopeOnMountOnly } from '@/hotkeys/hooks/useHotkeysScopeOnMountOnly';
|
||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { RawLink } from '@/ui/components/links/RawLink';
|
||||||
|
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
|
||||||
|
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
|
||||||
|
import { IconBuildingSkyscraper, IconLink, IconMap } from '@/ui/icons/index';
|
||||||
|
import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer';
|
||||||
|
import { ShowPageLeftContainer } from '@/ui/layout/show-page/containers/ShowPageLeftContainer';
|
||||||
|
import { ShowPageRightContainer } from '@/ui/layout/show-page/containers/ShowPageRightContainer';
|
||||||
|
import { ShowPageSummaryCard } from '@/ui/layout/show-page/ShowPageSummaryCard';
|
||||||
|
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||||
|
import { CommentableType } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export function CompanyShow() {
|
||||||
|
const companyId = useParams().companyId ?? '';
|
||||||
|
|
||||||
|
useHotkeysScopeOnMountOnly({
|
||||||
|
scope: InternalHotkeysScope.ShowPage,
|
||||||
|
customScopes: { 'command-menu': true, goto: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data } = useCompanyQuery(companyId);
|
||||||
|
const company = data?.findUniqueCompany;
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WithTopBarContainer
|
||||||
|
title={company?.name ?? ''}
|
||||||
|
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<ShowPageLeftContainer>
|
||||||
|
<ShowPageSummaryCard
|
||||||
|
logoOrAvatar={getLogoUrlFromDomainName(company?.domainName ?? '')}
|
||||||
|
title={company?.name ?? 'No name'}
|
||||||
|
date={company?.createdAt ?? ''}
|
||||||
|
/>
|
||||||
|
<PropertyBox extraPadding={true}>
|
||||||
|
<>
|
||||||
|
<PropertyBoxItem
|
||||||
|
icon={<IconLink />}
|
||||||
|
value={
|
||||||
|
<RawLink
|
||||||
|
href={
|
||||||
|
company?.domainName
|
||||||
|
? 'https://' + company?.domainName
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{company?.domainName}
|
||||||
|
</RawLink>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<PropertyBoxItem
|
||||||
|
icon={<IconMap />}
|
||||||
|
value={company?.address ? company?.address : 'No address'}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
</PropertyBox>
|
||||||
|
</ShowPageLeftContainer>
|
||||||
|
<ShowPageRightContainer>
|
||||||
|
<Timeline
|
||||||
|
entity={{ id: company?.id ?? '', type: CommentableType.Company }}
|
||||||
|
/>
|
||||||
|
</ShowPageRightContainer>
|
||||||
|
</>
|
||||||
|
</WithTopBarContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { expect } from '@storybook/jest';
|
|
||||||
import type { Meta } from '@storybook/react';
|
|
||||||
import { userEvent, within } from '@storybook/testing-library';
|
|
||||||
|
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
|
||||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
|
||||||
|
|
||||||
import { Companies } from '../Companies';
|
|
||||||
|
|
||||||
import { Story } from './Companies.stories';
|
|
||||||
|
|
||||||
const meta: Meta<typeof Companies> = {
|
|
||||||
title: 'Pages/Companies/Comments',
|
|
||||||
component: Companies,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
export const OpenCommentsSection: Story = {
|
|
||||||
render: getRenderWrapperForPage(<Companies />, '/companies'),
|
|
||||||
play: async ({ canvasElement }) => {
|
|
||||||
const canvas = within(canvasElement);
|
|
||||||
|
|
||||||
const firstRow = await canvas.findByTestId('row-id-1');
|
|
||||||
|
|
||||||
expect(firstRow).toBeDefined();
|
|
||||||
|
|
||||||
const commentsChip = await within(firstRow).findByTestId('comment-chip');
|
|
||||||
expect(commentsChip).toBeDefined();
|
|
||||||
|
|
||||||
userEvent.click(commentsChip);
|
|
||||||
const commentSection = await canvas.findByText('Comments');
|
|
||||||
expect(commentSection).toBeDefined();
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
80
front/src/pages/companies/__stories__/Company.stories.tsx
Normal file
80
front/src/pages/companies/__stories__/Company.stories.tsx
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { within } from '@storybook/testing-library';
|
||||||
|
import { graphql } from 'msw';
|
||||||
|
|
||||||
|
import {
|
||||||
|
GET_COMMENT_THREAD,
|
||||||
|
GET_COMMENT_THREADS_BY_TARGETS,
|
||||||
|
} from '@/comments/services';
|
||||||
|
import { CREATE_COMMENT_THREAD_WITH_COMMENT } from '@/comments/services/create';
|
||||||
|
import { GET_COMPANY } from '@/companies/services';
|
||||||
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
import { mockedCommentThreads } from '~/testing/mock-data/comment-threads';
|
||||||
|
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||||
|
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||||
|
|
||||||
|
import { CompanyShow } from '../CompanyShow';
|
||||||
|
|
||||||
|
const meta: Meta<typeof CompanyShow> = {
|
||||||
|
title: 'Pages/Companies/Company',
|
||||||
|
component: CompanyShow,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export type Story = StoryObj<typeof CompanyShow>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
render: getRenderWrapperForPage(
|
||||||
|
<CompanyShow />,
|
||||||
|
'/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||||
|
),
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const canvas = within(canvasElement);
|
||||||
|
const notesButton = await canvas.findByText('Notes');
|
||||||
|
await notesButton.click();
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
msw: [
|
||||||
|
...graphqlMocks,
|
||||||
|
graphql.mutation(
|
||||||
|
getOperationName(CREATE_COMMENT_THREAD_WITH_COMMENT) ?? '',
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.data({
|
||||||
|
createOneCommentThread: mockedCommentThreads[0],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
graphql.query(
|
||||||
|
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.data({
|
||||||
|
findManyCommentThreads: mockedCommentThreads,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
graphql.query(
|
||||||
|
getOperationName(GET_COMMENT_THREAD) ?? '',
|
||||||
|
(req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.data({
|
||||||
|
findManyCommentThreads: mockedCommentThreads[0],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
graphql.query(getOperationName(GET_COMPANY) ?? '', (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.data({
|
||||||
|
findUniqueCompany: mockedCompaniesData[0],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
51
front/src/pages/people/PersonShow.tsx
Normal file
51
front/src/pages/people/PersonShow.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
|
import { Timeline } from '@/comments/components/timeline/Timeline';
|
||||||
|
import { usePersonQuery } from '@/people/services';
|
||||||
|
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
|
||||||
|
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
|
||||||
|
import { IconLink, IconUser } from '@/ui/icons/index';
|
||||||
|
import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer';
|
||||||
|
import { ShowPageLeftContainer } from '@/ui/layout/show-page/containers/ShowPageLeftContainer';
|
||||||
|
import { ShowPageRightContainer } from '@/ui/layout/show-page/containers/ShowPageRightContainer';
|
||||||
|
import { ShowPageSummaryCard } from '@/ui/layout/show-page/ShowPageSummaryCard';
|
||||||
|
import { CommentableType } from '~/generated/graphql';
|
||||||
|
|
||||||
|
export function PersonShow() {
|
||||||
|
const personId = useParams().personId ?? '';
|
||||||
|
|
||||||
|
const { data } = usePersonQuery(personId);
|
||||||
|
const person = data?.findUniquePerson;
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WithTopBarContainer
|
||||||
|
title={person?.firstName ?? ''}
|
||||||
|
icon={<IconUser size={theme.icon.size.md} />}
|
||||||
|
>
|
||||||
|
<>
|
||||||
|
<ShowPageLeftContainer>
|
||||||
|
<ShowPageSummaryCard
|
||||||
|
title={person?.displayName ?? 'No name'}
|
||||||
|
date={person?.createdAt ?? ''}
|
||||||
|
/>
|
||||||
|
<PropertyBox extraPadding={true}>
|
||||||
|
<>
|
||||||
|
<PropertyBoxItem
|
||||||
|
icon={<IconLink />}
|
||||||
|
value={person?.firstName ?? 'No First name'}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
</PropertyBox>
|
||||||
|
</ShowPageLeftContainer>
|
||||||
|
<ShowPageRightContainer>
|
||||||
|
<Timeline
|
||||||
|
entity={{ id: person?.id ?? '', type: CommentableType.Person }}
|
||||||
|
/>
|
||||||
|
</ShowPageRightContainer>
|
||||||
|
</>
|
||||||
|
</WithTopBarContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,38 +0,0 @@
|
|||||||
import { expect } from '@storybook/jest';
|
|
||||||
import type { Meta } from '@storybook/react';
|
|
||||||
import { userEvent, within } from '@storybook/testing-library';
|
|
||||||
|
|
||||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
|
||||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
|
||||||
|
|
||||||
import { People } from '../People';
|
|
||||||
|
|
||||||
import { Story } from './People.stories';
|
|
||||||
|
|
||||||
const meta: Meta<typeof People> = {
|
|
||||||
title: 'Pages/People/Comments',
|
|
||||||
component: People,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default meta;
|
|
||||||
|
|
||||||
export const OpenCommentsSection: Story = {
|
|
||||||
render: getRenderWrapperForPage(<People />, '/people'),
|
|
||||||
play: async ({ canvasElement }) => {
|
|
||||||
const canvas = within(canvasElement);
|
|
||||||
|
|
||||||
const firstRow = await canvas.findByTestId('row-id-1');
|
|
||||||
|
|
||||||
expect(firstRow).toBeDefined();
|
|
||||||
|
|
||||||
const commentsChip = await within(firstRow).findByTestId('comment-chip');
|
|
||||||
expect(commentsChip).toBeDefined();
|
|
||||||
|
|
||||||
userEvent.click(commentsChip);
|
|
||||||
const commentSection = await canvas.findByText('Comments');
|
|
||||||
expect(commentSection).toBeDefined();
|
|
||||||
},
|
|
||||||
parameters: {
|
|
||||||
msw: graphqlMocks,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
25
front/src/pages/people/__stories__/Person.stories.tsx
Normal file
25
front/src/pages/people/__stories__/Person.stories.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
|
||||||
|
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||||
|
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||||
|
|
||||||
|
import { PersonShow } from '../PersonShow';
|
||||||
|
|
||||||
|
const meta: Meta<typeof PersonShow> = {
|
||||||
|
title: 'Pages/People/Person',
|
||||||
|
component: PersonShow,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export type Story = StoryObj<typeof PersonShow>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
render: getRenderWrapperForPage(
|
||||||
|
<PersonShow />,
|
||||||
|
'/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||||
|
),
|
||||||
|
parameters: {
|
||||||
|
msw: graphqlMocks,
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Comment,
|
||||||
CommentableType,
|
CommentableType,
|
||||||
CommentThread,
|
CommentThread,
|
||||||
CommentThreadTarget,
|
CommentThreadTarget,
|
||||||
@ -6,8 +7,21 @@ import {
|
|||||||
|
|
||||||
type MockedCommentThread = Pick<
|
type MockedCommentThread = Pick<
|
||||||
CommentThread,
|
CommentThread,
|
||||||
'id' | 'createdAt' | 'updatedAt' | '__typename'
|
| 'id'
|
||||||
|
| 'createdAt'
|
||||||
|
| 'updatedAt'
|
||||||
|
| '__typename'
|
||||||
|
| 'body'
|
||||||
|
| 'title'
|
||||||
|
| 'authorId'
|
||||||
> & {
|
> & {
|
||||||
|
author: {
|
||||||
|
__typename?: 'User' | undefined;
|
||||||
|
id: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
};
|
||||||
|
comments: Array<Pick<Comment, 'body'>>;
|
||||||
commentThreadTargets: Array<
|
commentThreadTargets: Array<
|
||||||
Pick<
|
Pick<
|
||||||
CommentThreadTarget,
|
CommentThreadTarget,
|
||||||
@ -27,6 +41,15 @@ export const mockedCommentThreads: Array<MockedCommentThread> = [
|
|||||||
id: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
|
id: '89bb825c-171e-4bcc-9cf7-43448d6fb230',
|
||||||
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
||||||
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
updatedAt: '2023-04-26T10:23:42.33625+00:00',
|
||||||
|
title: 'My very first note',
|
||||||
|
body: null,
|
||||||
|
author: {
|
||||||
|
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
|
||||||
|
firstName: 'Charles',
|
||||||
|
lastName: 'Test',
|
||||||
|
},
|
||||||
|
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
|
||||||
|
comments: [],
|
||||||
commentThreadTargets: [
|
commentThreadTargets: [
|
||||||
{
|
{
|
||||||
id: '89bb825c-171e-4bcc-9cf7-43448d6fb300',
|
id: '89bb825c-171e-4bcc-9cf7-43448d6fb300',
|
||||||
@ -63,6 +86,15 @@ export const mockedCommentThreads: Array<MockedCommentThread> = [
|
|||||||
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
|
title: 'Another note',
|
||||||
|
body: null,
|
||||||
|
author: {
|
||||||
|
id: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
|
||||||
|
firstName: 'Charles',
|
||||||
|
lastName: 'Test',
|
||||||
|
},
|
||||||
|
authorId: '374fe3a5-df1e-4119-afe0-2a62a2ba481e',
|
||||||
|
comments: [],
|
||||||
commentThreadTargets: [
|
commentThreadTargets: [
|
||||||
{
|
{
|
||||||
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
id: '89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type MockedCompany = Pick<
|
|||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
| 'address'
|
| 'address'
|
||||||
| 'employees'
|
| 'employees'
|
||||||
| '_commentCount'
|
| '_commentThreadCount'
|
||||||
> & {
|
> & {
|
||||||
accountOwner: Pick<
|
accountOwner: Pick<
|
||||||
User,
|
User,
|
||||||
@ -25,7 +25,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:08:54.724515+00:00',
|
createdAt: '2023-04-26T10:08:54.724515+00:00',
|
||||||
address: '17 rue de clignancourt',
|
address: '17 rue de clignancourt',
|
||||||
employees: 12,
|
employees: 12,
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
accountOwner: {
|
accountOwner: {
|
||||||
email: 'charles@test.com',
|
email: 'charles@test.com',
|
||||||
displayName: 'Charles Test',
|
displayName: 'Charles Test',
|
||||||
@ -43,7 +43,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
createdAt: '2023-04-26T10:12:42.33625+00:00',
|
||||||
address: '',
|
address: '',
|
||||||
employees: 1,
|
employees: 1,
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
@ -54,7 +54,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:10:32.530184+00:00',
|
createdAt: '2023-04-26T10:10:32.530184+00:00',
|
||||||
address: '',
|
address: '',
|
||||||
employees: 1,
|
employees: 1,
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
@ -65,7 +65,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-03-21T06:30:25.39474+00:00',
|
createdAt: '2023-03-21T06:30:25.39474+00:00',
|
||||||
address: '',
|
address: '',
|
||||||
employees: 10,
|
employees: 10,
|
||||||
_commentCount: 0,
|
_commentThreadCount: 0,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
@ -76,7 +76,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:13:29.712485+00:00',
|
createdAt: '2023-04-26T10:13:29.712485+00:00',
|
||||||
address: '10 rue de la Paix',
|
address: '10 rue de la Paix',
|
||||||
employees: 1,
|
employees: 1,
|
||||||
_commentCount: 2,
|
_commentThreadCount: 2,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
@ -87,7 +87,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:09:25.656555+00:00',
|
createdAt: '2023-04-26T10:09:25.656555+00:00',
|
||||||
address: '',
|
address: '',
|
||||||
employees: 1,
|
employees: 1,
|
||||||
_commentCount: 13,
|
_commentThreadCount: 13,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
@ -98,7 +98,7 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
|||||||
createdAt: '2023-04-26T10:09:25.656555+00:00',
|
createdAt: '2023-04-26T10:09:25.656555+00:00',
|
||||||
address: '',
|
address: '',
|
||||||
employees: 1,
|
employees: 1,
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
accountOwner: null,
|
accountOwner: null,
|
||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -9,7 +9,7 @@ type MockedPerson = Pick<
|
|||||||
| '__typename'
|
| '__typename'
|
||||||
| 'phone'
|
| 'phone'
|
||||||
| 'city'
|
| 'city'
|
||||||
| '_commentCount'
|
| '_commentThreadCount'
|
||||||
| 'createdAt'
|
| 'createdAt'
|
||||||
> & {
|
> & {
|
||||||
company: Pick<Company, 'id' | 'name' | 'domainName' | '__typename'>;
|
company: Pick<Company, 'id' | 'name' | 'domainName' | '__typename'>;
|
||||||
@ -29,7 +29,7 @@ export const mockedPeopleData: Array<MockedPerson> = [
|
|||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
phone: '06 12 34 56 78',
|
phone: '06 12 34 56 78',
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
||||||
|
|
||||||
city: 'Paris',
|
city: 'Paris',
|
||||||
@ -47,7 +47,7 @@ export const mockedPeopleData: Array<MockedPerson> = [
|
|||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
phone: '06 12 34 56 78',
|
phone: '06 12 34 56 78',
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
||||||
|
|
||||||
city: 'Paris',
|
city: 'Paris',
|
||||||
@ -65,7 +65,7 @@ export const mockedPeopleData: Array<MockedPerson> = [
|
|||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
phone: '06 12 34 56 78',
|
phone: '06 12 34 56 78',
|
||||||
_commentCount: 1,
|
_commentThreadCount: 1,
|
||||||
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
||||||
|
|
||||||
city: 'Paris',
|
city: 'Paris',
|
||||||
@ -83,7 +83,7 @@ export const mockedPeopleData: Array<MockedPerson> = [
|
|||||||
__typename: 'Company',
|
__typename: 'Company',
|
||||||
},
|
},
|
||||||
phone: '06 12 34 56 78',
|
phone: '06 12 34 56 78',
|
||||||
_commentCount: 2,
|
_commentThreadCount: 2,
|
||||||
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
createdAt: '2023-04-20T13:20:09.158312+00:00',
|
||||||
|
|
||||||
city: 'Paris',
|
city: 'Paris',
|
||||||
|
|||||||
1655
front/yarn.lock
1655
front/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,15 @@ export class CommentThreadCountAggregateInput {
|
|||||||
@HideField()
|
@HideField()
|
||||||
workspaceId?: true;
|
workspaceId?: true;
|
||||||
|
|
||||||
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
authorId?: true;
|
||||||
|
|
||||||
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
body?: true;
|
||||||
|
|
||||||
|
@Field(() => Boolean, {nullable:true})
|
||||||
|
title?: true;
|
||||||
|
|
||||||
@HideField()
|
@HideField()
|
||||||
deletedAt?: true;
|
deletedAt?: true;
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,15 @@ export class CommentThreadCountAggregate {
|
|||||||
@HideField()
|
@HideField()
|
||||||
workspaceId!: number;
|
workspaceId!: number;
|
||||||
|
|
||||||
|
@Field(() => Int, {nullable:false})
|
||||||
|
authorId!: number;
|
||||||
|
|
||||||
|
@Field(() => Int, {nullable:false})
|
||||||
|
body!: number;
|
||||||
|
|
||||||
|
@Field(() => Int, {nullable:false})
|
||||||
|
title!: number;
|
||||||
|
|
||||||
@HideField()
|
@HideField()
|
||||||
deletedAt!: number;
|
deletedAt!: number;
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,15 @@ export class CommentThreadCountOrderByAggregateInput {
|
|||||||
@HideField()
|
@HideField()
|
||||||
workspaceId?: keyof typeof SortOrder;
|
workspaceId?: keyof typeof SortOrder;
|
||||||
|
|
||||||
|
@Field(() => SortOrder, {nullable:true})
|
||||||
|
authorId?: keyof typeof SortOrder;
|
||||||
|
|
||||||
|
@Field(() => SortOrder, {nullable:true})
|
||||||
|
body?: keyof typeof SortOrder;
|
||||||
|
|
||||||
|
@Field(() => SortOrder, {nullable:true})
|
||||||
|
title?: keyof typeof SortOrder;
|
||||||
|
|
||||||
@HideField()
|
@HideField()
|
||||||
deletedAt?: keyof typeof SortOrder;
|
deletedAt?: keyof typeof SortOrder;
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user