feat: create default views on workspace creation + add views seed (#1313)

Closes #1311
This commit is contained in:
Thaïs 2023-08-25 21:17:28 +02:00 committed by GitHub
parent 8a3a176571
commit 209e8b64d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 356 additions and 16 deletions

View File

@ -96,7 +96,7 @@ export const TableViewsDropdownButton = ({
const handleViewSelect = useRecoilCallback(
({ set, snapshot }) =>
async (viewId?: string) => {
async (viewId: string) => {
const savedColumns = await snapshot.getPromise(
savedTableColumnsScopedState(viewId),
);
@ -164,7 +164,7 @@ export const TableViewsDropdownButton = ({
<StyledViewIcon size={theme.icon.size.md} />
{currentView?.name || defaultViewName}{' '}
<StyledDropdownLabelAdornments>
· {views.length + 1} <IconChevronDown size={theme.icon.size.sm} />
· {views.length} <IconChevronDown size={theme.icon.size.sm} />
</StyledDropdownLabelAdornments>
</>
}
@ -175,10 +175,6 @@ export const TableViewsDropdownButton = ({
HotkeyScope={HotkeyScope}
>
<StyledDropdownMenuItemsContainer>
<DropdownMenuItem onClick={() => handleViewSelect(undefined)}>
<IconList size={theme.icon.size.md} />
{defaultViewName}
</DropdownMenuItem>
{views.map((view) => (
<DropdownMenuItem
key={view.id}

View File

@ -68,7 +68,7 @@ export const useTableViewFields = ({
columns: ViewFieldDefinition<ViewFieldMetadata>[],
viewId = currentViewId,
) => {
if (!columns.length) return;
if (!viewId || !columns.length) return;
return createViewFieldsMutation({
variables: {
@ -84,7 +84,7 @@ export const useTableViewFields = ({
const updateViewFields = useCallback(
(columns: ViewFieldDefinition<ViewFieldMetadata>[]) => {
if (!columns.length) return;
if (!currentViewId || !columns.length) return;
return Promise.all(
columns.map((column) =>
@ -100,10 +100,11 @@ export const useTableViewFields = ({
),
);
},
[updateViewFieldMutation],
[currentViewId, updateViewFieldMutation],
);
const { refetch } = useGetViewFieldsQuery({
skip: !currentViewId,
variables: {
orderBy: { index: SortOrder.Asc },
where: {
@ -139,6 +140,8 @@ export const useTableViewFields = ({
});
const persistColumns = useCallback(async () => {
if (!currentViewId) return;
const viewFieldsToUpdate = columns.filter(
(column) =>
savedColumnsById[column.id] &&
@ -148,7 +151,7 @@ export const useTableViewFields = ({
await updateViewFields(viewFieldsToUpdate);
return refetch();
}, [columns, refetch, savedColumnsById, updateViewFields]);
}, [columns, currentViewId, refetch, savedColumnsById, updateViewFields]);
return { createViewFields, persistColumns };
};

View File

@ -2,6 +2,7 @@ import { useCallback } from 'react';
import { TableRecoilScopeContext } from '@/ui/table/states/recoil-scope-contexts/TableRecoilScopeContext';
import {
currentTableViewIdState,
type TableView,
tableViewsByIdState,
tableViewsState,
@ -24,6 +25,10 @@ export const useViews = ({
objectId: 'company' | 'person';
onViewCreate: (viewId: string) => Promise<void>;
}) => {
const [currentViewId, setCurrentViewId] = useRecoilScopedState(
currentTableViewIdState,
TableRecoilScopeContext,
);
const [views, setViews] = useRecoilScopedState(
tableViewsState,
TableRecoilScopeContext,
@ -102,6 +107,8 @@ export const useViews = ({
}));
if (!isDeeplyEqual(views, nextViews)) setViews(nextViews);
if (nextViews.length && !currentViewId) setCurrentViewId(nextViews[0].id);
},
});

View File

@ -0,0 +1,111 @@
[
{
"name": "All Companies",
"objectId": "company",
"type": "Table",
"fields": [
{
"fieldName": "Name",
"sizeInPx": 180,
"isVisible": true
},
{
"fieldName": "URL",
"sizeInPx": 100,
"isVisible": true
},
{
"fieldName": "Account Owner",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Creation",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Employees",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "LinkedIn",
"sizeInPx": 170,
"isVisible": true
},
{
"fieldName": "Address",
"sizeInPx": 170,
"isVisible": true
},
{
"fieldName": "ICP",
"sizeInPx": 150,
"isVisible": false
},
{
"fieldName": "ARR",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Twitter",
"sizeInPx": 150,
"isVisible": false
}
]
},
{
"name": "All People",
"objectId": "person",
"type": "Table",
"fields": [
{
"fieldName": "People",
"sizeInPx": 210,
"isVisible": true
},
{
"fieldName": "Email",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Company",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Phone",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Creation",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "City",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Job title",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "LinkedIn",
"sizeInPx": 150,
"isVisible": true
},
{
"fieldName": "Twitter",
"sizeInPx": 150,
"isVisible": true
}
]
}
]

View File

@ -1,6 +1,9 @@
import { Injectable } from '@nestjs/common';
import type { ViewType } from '@prisma/client';
import { PrismaService } from 'src/database/prisma.service';
import seedViews from 'src/core/view/seed-data/views.json';
@Injectable()
export class ViewService {
@ -36,4 +39,29 @@ export class ViewService {
// GroupBy
groupBy = this.prismaService.client.view.groupBy;
// Custom
createDefaultViews({ workspaceId }: { workspaceId: string }) {
return Promise.all(
seedViews.map(async ({ fields, ...viewInput }) => {
const view = await this.create({
data: {
...viewInput,
type: viewInput.type as ViewType,
workspace: { connect: { id: workspaceId } },
},
});
await this.prismaService.client.viewField.createMany({
data: fields.map((viewField, index) => ({
...viewField,
objectName: view.objectId,
index: index + 1,
viewId: view.id,
workspaceId,
})),
});
}),
);
}
}

View File

@ -20,5 +20,6 @@ import { ViewFilterResolver } from './resolvers/view-filter.resolver';
ViewFilterResolver,
ViewSortResolver,
],
exports: [ViewService],
})
export class ViewModule {}

View File

@ -7,6 +7,7 @@ import { PipelineStageService } from 'src/core/pipeline/services/pipeline-stage.
import { PersonService } from 'src/core/person/person.service';
import { CompanyService } from 'src/core/company/company.service';
import { PipelineProgressService } from 'src/core/pipeline/services/pipeline-progress.service';
import { ViewService } from 'src/core/view/services/view.service';
import { WorkspaceService } from './workspace.service';
@ -41,6 +42,10 @@ describe('WorkspaceService', () => {
provide: PipelineProgressService,
useValue: {},
},
{
provide: ViewService,
useValue: {},
},
],
}).compile();

View File

@ -1,14 +1,15 @@
import { Injectable } from '@nestjs/common';
import { v4 } from 'uuid';
import { Prisma } from '@prisma/client';
import { v4 } from 'uuid';
import { PipelineStageService } from 'src/core/pipeline/services/pipeline-stage.service';
import { PipelineProgressService } from 'src/core/pipeline/services/pipeline-progress.service';
import { PipelineService } from 'src/core/pipeline/services/pipeline.service';
import { PrismaService } from 'src/database/prisma.service';
import { CompanyService } from 'src/core/company/company.service';
import { PersonService } from 'src/core/person/person.service';
import { PipelineProgressService } from 'src/core/pipeline/services/pipeline-progress.service';
import { PipelineStageService } from 'src/core/pipeline/services/pipeline-stage.service';
import { PipelineService } from 'src/core/pipeline/services/pipeline.service';
import { ViewService } from 'src/core/view/services/view.service';
import { PrismaService } from 'src/database/prisma.service';
import { assert } from 'src/utils/assert';
@Injectable()
@ -20,6 +21,7 @@ export class WorkspaceService {
private readonly personService: PersonService,
private readonly pipelineStageService: PipelineStageService,
private readonly pipelineProgressService: PipelineProgressService,
private readonly viewService: ViewService,
) {}
// Find
@ -83,6 +85,11 @@ export class WorkspaceService {
workspaceId: workspace.id,
});
// Create default views
await this.viewService.createDefaultViews({
workspaceId: workspace.id,
});
return workspace;
}

View File

@ -4,6 +4,7 @@ import { FileUploadService } from 'src/core/file/services/file-upload.service';
import { PipelineModule } from 'src/core/pipeline/pipeline.module';
import { CompanyModule } from 'src/core/company/company.module';
import { PersonModule } from 'src/core/person/person.module';
import { ViewModule } from 'src/core/view/view.module';
import { WorkspaceService } from './services/workspace.service';
import { WorkspaceMemberService } from './services/workspace-member.service';
@ -11,7 +12,7 @@ import { WorkspaceMemberResolver } from './resolvers/workspace-member.resolver';
import { WorkspaceResolver } from './resolvers/workspace.resolver';
@Module({
imports: [PipelineModule, CompanyModule, PersonModule],
imports: [PipelineModule, CompanyModule, PersonModule, ViewModule],
providers: [
WorkspaceService,
FileUploadService,

View File

@ -6,6 +6,7 @@ import { seedPeople } from './people';
import { seedComments } from './comments';
import { seedUsers } from './users';
import { seedPipelines } from './pipelines';
import { seedViews } from './views';
const seed = async () => {
const prisma = new PrismaClient();
@ -15,6 +16,7 @@ const seed = async () => {
await seedPeople(prisma);
await seedComments(prisma);
await seedPipelines(prisma);
await seedViews(prisma);
await prisma.$disconnect();
};

View File

@ -0,0 +1,179 @@
import { PrismaClient } from '@prisma/client';
export const seedViews = async (prisma: PrismaClient) => {
const workspaceId = 'twenty-7ed9d212-1c25-4d02-bf25-6aeccf7ea419';
const companyViewId = 'twenty-5e924b69-a619-41bf-bd31-a9e8551fc9d1';
const personViewId = 'twenty-db9e6c85-c091-4fd6-88b1-c1830f5e90d1';
await prisma.view.upsert({
where: { id: companyViewId },
update: {},
create: {
id: companyViewId,
name: 'All Companies',
objectId: 'company',
type: 'Table',
workspaceId,
},
});
await Promise.all(
[
{
id: 'twenty-388833ba-1343-49d7-9092-065f92e0e5fa',
fieldName: 'Name',
sizeInPx: 180,
isVisible: true,
},
{
id: 'twenty-fdbb7a60-18ac-4d52-83b8-399eb6055ec6',
fieldName: 'URL',
sizeInPx: 100,
isVisible: true,
},
{
id: 'twenty-cc77beef-af99-4cd2-86dd-0230f8565ed5',
fieldName: 'Account Owner',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-28537b67-8b78-4885-903d-f749f34883b1',
fieldName: 'Creation',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-59e6624d-9a4d-492d-a0f2-52f51f69d004',
fieldName: 'Employees',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-2c4ee8b9-aacd-42dd-b422-22eca03aab5a',
fieldName: 'LinkedIn',
sizeInPx: 170,
isVisible: true,
},
{
id: 'twenty-b83e299f-7098-4748-a39e-431cca2907ab',
fieldName: 'Address',
sizeInPx: 170,
isVisible: true,
},
{
id: 'twenty-acef1246-8461-4e34-96b9-f326d598d655',
fieldName: 'ICP',
sizeInPx: 150,
isVisible: false,
},
{
id: 'twenty-971828c5-8167-4997-ae13-3b7895faa6f2',
fieldName: 'ARR',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-90977d8a-328d-4f69-98e8-8c69723c5a18',
fieldName: 'Twitter',
sizeInPx: 150,
isVisible: false,
},
].map((viewField, index) =>
prisma.viewField.upsert({
where: { id: viewField.id },
update: {},
create: {
...viewField,
index: index + 1,
objectName: 'company',
viewId: companyViewId,
workspaceId,
},
}),
),
);
await prisma.view.upsert({
where: { id: personViewId },
update: {},
create: {
id: personViewId,
name: 'All People',
objectId: 'person',
type: 'Table',
workspaceId,
},
});
await Promise.all(
[
{
id: 'twenty-fc3461b4-661d-492e-8907-61004a41cca6',
fieldName: 'People',
sizeInPx: 210,
isVisible: true,
},
{
id: 'twenty-4724d413-4343-4528-b8c4-4431910722f8',
fieldName: 'Email',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-fbb16b08-5a58-4a69-8bd0-a6d267994042',
fieldName: 'Company',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-1bad57bb-6627-40f8-8c75-bb5902892273',
fieldName: 'Phone',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-3544d797-740b-4e0b-8226-134bf38da256',
fieldName: 'Creation',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-4b6d48fb-17e2-4071-8565-d512f84656d5',
fieldName: 'City',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-418849cc-aa5c-4835-822b-c0dfb076106b',
fieldName: 'Job title',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-7591af5d-e081-4afa-94bb-09bd0e517850',
fieldName: 'LinkedIn',
sizeInPx: 150,
isVisible: true,
},
{
id: 'twenty-e7baeb3d-8ef3-4e61-89d6-60f64b1d52c5',
fieldName: 'Twitter',
sizeInPx: 150,
isVisible: true,
},
].map((viewField, index) =>
prisma.viewField.upsert({
where: { id: viewField.id },
update: {},
create: {
...viewField,
index: index + 1,
objectName: 'person',
viewId: personViewId,
workspaceId,
},
}),
),
);
};