Deprecate old relations completely (#12482)

# What

Fully deprecate old relations because we have one bug tied to it and it
make the codebase complex

# How I've made this PR:
1. remove metadata datasource (we only keep 'core') => this was causing
extra complexity in the refactor + flaky reset
2. merge dev and demo datasets => as I needed to update the tests which
is very painful, I don't want to do it twice
3. remove all code tied to RELATION_METADATA /
relation-metadata.resolver, or anything tied to the old relation system
4. Remove ONE_TO_ONE and MANY_TO_MANY that are not supported
5. fix impacts on the different areas : see functional testing below 

# Functional testing

## Functional testing from the front-end:
1. Database Reset 
2. Sign In 
3. Workspace sign-up 
5. Browsing table / kanban / show 
6. Assigning a record in a one to many / in a many to one 
7. Deleting a record involved in a relation  => broken but not tied to
this PR
8. "Add new" from relation picker  => broken but not tied to this PR
9. Creating a Task / Note, Updating a Task / Note relations, Deleting a
Task / Note (from table, show page, right drawer)  => broken but not
tied to this PR
10. creating a relation from settings (custom / standard x oneToMany /
manyToOne) 
11. updating a relation from settings should not be possible 
12. deleting a relation from settings (custom / standard x oneToMany /
manyToOne) 
13. Make sure timeline activity still work (relation were involved
there), espacially with Task / Note => to be double checked  => Cannot
convert undefined or null to object
14. Workspace deletion / User deletion  
15. CSV Import should keep working  
16. Permissions: I have tested without permissions V2 as it's still hard
to test v2 work and it's not in prod yet 
17. Workflows global test  

## From the API:
1. Review open-api documentation (REST)  
2. Make sure REST Api are still able to fetch relations ==> won't do, we
have a coupling Get/Update/Create there, this requires refactoring
3. Make sure REST Api is still able to update / remove relation => won't
do same

## Automated tests
1. lint + typescript 
2. front unit tests: 
3. server unit tests 2 
4. front stories: 
5. server integration: 
6. chromatic check : expected 0
7. e2e check : expected no more that current failures

## Remove // Todos
1. All are captured by functional tests above, nothing additional to do

## (Un)related regressions
1. Table loading state is not working anymore, we see the empty state
before table content
2. Filtering by Creator Tim Ap return empty results
3. Not possible to add Tasks / Notes / Files from show page

# Result

## New seeds that can be easily extended
<img width="1920" alt="image"
src="https://github.com/user-attachments/assets/d290d130-2a5f-44e6-b419-7e42a89eec4b"
/>

## -5k lines of code
## No more 'metadata' dataSource (we only have 'core)
## No more relationMetadata (I haven't drop the table yet it's not
referenced in the code anymore)
## We are ready to fix the 6 months lag between current API results and
our mocked tests
## No more bug on relation creation / deletion

---------

Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Charles Bochet
2025-06-10 16:45:27 +02:00
committed by GitHub
parent 264861e020
commit a68895189c
426 changed files with 48870 additions and 54125 deletions

View File

@ -0,0 +1,33 @@
import { DataSource } from 'typeorm';
const tableName = 'billingSubscription';
export const seedBillingSubscriptions = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
await dataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, [
'workspaceId',
'stripeCustomerId',
'stripeSubscriptionId',
'status',
'metadata',
])
.orIgnore()
.values([
{
workspaceId,
stripeCustomerId: 'cus_default0',
stripeSubscriptionId: 'sub_default0',
status: 'active',
metadata: {
workspaceId,
},
},
])
.execute();
};

View File

@ -0,0 +1,78 @@
import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { Repository } from 'typeorm';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service';
import { USER_WORKSPACE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util';
import {
SEED_ACME_WORKSPACE_ID,
SEED_APPLE_WORKSPACE_ID,
} from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspaces.util';
@Injectable()
export class DevSeederPermissionsService {
private readonly logger = new Logger(DevSeederPermissionsService.name);
constructor(
private readonly roleService: RoleService,
private readonly userRoleService: UserRoleService,
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
) {}
public async initPermissions(workspaceId: string) {
const adminRole = await this.roleService.createAdminRole({
workspaceId,
});
let adminUserWorkspaceId: string | undefined;
let memberUserWorkspaceId: string | undefined;
if (workspaceId === SEED_APPLE_WORKSPACE_ID) {
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM;
memberUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.JONY;
// Create guest role only in this workspace
const guestRole = await this.roleService.createGuestRole({
workspaceId,
});
await this.userRoleService.assignRoleToUserWorkspace({
workspaceId,
userWorkspaceId: USER_WORKSPACE_DATA_SEED_IDS.PHIL,
roleId: guestRole.id,
});
} else if (workspaceId === SEED_ACME_WORKSPACE_ID) {
adminUserWorkspaceId = USER_WORKSPACE_DATA_SEED_IDS.TIM_ACME;
}
if (adminUserWorkspaceId) {
await this.userRoleService.assignRoleToUserWorkspace({
workspaceId,
userWorkspaceId: adminUserWorkspaceId,
roleId: adminRole.id,
});
}
const memberRole = await this.roleService.createMemberRole({
workspaceId,
});
await this.workspaceRepository.update(workspaceId, {
defaultRoleId: memberRole.id,
activationStatus: WorkspaceActivationStatus.ACTIVE,
});
if (memberUserWorkspaceId) {
await this.userRoleService.assignRoleToUserWorkspace({
workspaceId,
userWorkspaceId: memberUserWorkspaceId,
roleId: memberRole.id,
});
}
}
}

View File

@ -0,0 +1,42 @@
import { DataSource } from 'typeorm';
import { seedBillingSubscriptions } from 'src/engine/workspace-manager/dev-seeder/core/billing/utils/seed-billing-subscriptions.util';
import { seedFeatureFlags } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util';
import { seedUserWorkspaces } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-user-workspaces.util';
import { seedUsers } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-users.util';
import { seedWorkspaces } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspaces.util';
type SeedCoreSchemaArgs = {
dataSource: DataSource;
workspaceId: string;
appVersion: string | undefined;
seedBilling?: boolean;
seedFeatureFlags?: boolean;
};
export const seedCoreSchema = async ({
appVersion,
dataSource,
workspaceId,
seedBilling = true,
seedFeatureFlags: shouldSeedFeatureFlags = true,
}: SeedCoreSchemaArgs) => {
const schemaName = 'core';
await seedWorkspaces({
dataSource,
schemaName,
workspaceId,
appVersion,
});
await seedUsers(dataSource, schemaName);
await seedUserWorkspaces(dataSource, schemaName, workspaceId);
if (shouldSeedFeatureFlags) {
await seedFeatureFlags(dataSource, schemaName, workspaceId);
}
if (seedBilling) {
await seedBillingSubscriptions(dataSource, schemaName, workspaceId);
}
};

View File

@ -0,0 +1,63 @@
import { DataSource } from 'typeorm';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
const tableName = 'featureFlag';
export const seedFeatureFlags = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
await dataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, ['key', 'workspaceId', 'value'])
.orIgnore()
.values([
{
key: FeatureFlagKey.IS_AIRTABLE_INTEGRATION_ENABLED,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_POSTGRESQL_INTEGRATION_ENABLED,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_STRIPE_INTEGRATION_ENABLED,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_WORKFLOW_ENABLED,
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKey.IS_UNIQUE_INDEXES_ENABLED,
workspaceId: workspaceId,
value: false,
},
{
key: FeatureFlagKey.IS_AI_ENABLED,
workspaceId: workspaceId,
value: true,
},
])
.execute();
};
export const deleteFeatureFlags = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
await dataSource
.createQueryBuilder()
.delete()
.from(`${schemaName}.${tableName}`)
.where(`"${tableName}"."workspaceId" = :workspaceId`, { workspaceId })
.execute();
};

View File

@ -0,0 +1,90 @@
import { DataSource } from 'typeorm';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { USER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-users.util';
import {
SEED_ACME_WORKSPACE_ID,
SEED_APPLE_WORKSPACE_ID,
} from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-workspaces.util';
const tableName = 'userWorkspace';
export const USER_WORKSPACE_DATA_SEED_IDS = {
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b035',
JONY: '20202020-3957-4908-9c36-2929a23f8353',
PHIL: '20202020-7169-42cf-bc47-1cfef15264b1',
TIM_ACME: '20202020-e10a-4c27-a90b-b08c57b02d44',
JONY_ACME: '20202020-e10a-4c27-a90b-b08c57b02d45',
PHIL_ACME: '20202020-e10a-4c27-a90b-b08c57b02d46',
};
export const seedUserWorkspaces = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
let userWorkspaces: Pick<UserWorkspace, 'id' | 'userId' | 'workspaceId'>[] =
[];
if (workspaceId === SEED_APPLE_WORKSPACE_ID) {
userWorkspaces = [
{
id: USER_WORKSPACE_DATA_SEED_IDS.TIM,
userId: USER_DATA_SEED_IDS.TIM,
workspaceId,
},
{
id: USER_WORKSPACE_DATA_SEED_IDS.JONY,
userId: USER_DATA_SEED_IDS.JONY,
workspaceId,
},
{
id: USER_WORKSPACE_DATA_SEED_IDS.PHIL,
userId: USER_DATA_SEED_IDS.PHIL,
workspaceId,
},
];
}
if (workspaceId === SEED_ACME_WORKSPACE_ID) {
userWorkspaces = [
{
id: USER_WORKSPACE_DATA_SEED_IDS.TIM_ACME,
userId: USER_DATA_SEED_IDS.TIM,
workspaceId,
},
{
id: USER_WORKSPACE_DATA_SEED_IDS.JONY_ACME,
userId: USER_DATA_SEED_IDS.JONY,
workspaceId,
},
{
id: USER_WORKSPACE_DATA_SEED_IDS.PHIL_ACME,
userId: USER_DATA_SEED_IDS.PHIL,
workspaceId,
},
];
}
await dataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, ['id', 'userId', 'workspaceId'])
.orIgnore()
.values(userWorkspaces)
.execute();
};
export const deleteUserWorkspaces = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
await dataSource
.createQueryBuilder()
.delete()
.from(`${schemaName}.${tableName}`)
.where(`"${tableName}"."workspaceId" = :workspaceId`, {
workspaceId,
})
.execute();
};

View File

@ -0,0 +1,62 @@
import { DataSource } from 'typeorm';
const tableName = 'user';
export const USER_DATA_SEED_IDS = {
TIM: '20202020-9e3b-46d4-a556-88b9ddc2b034',
JONY: '20202020-3957-4908-9c36-2929a23f8357',
PHIL: '20202020-7169-42cf-bc47-1cfef15264b8',
};
export const seedUsers = async (dataSource: DataSource, schemaName: string) => {
await dataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, [
'id',
'firstName',
'lastName',
'email',
'passwordHash',
'canImpersonate',
'canAccessFullAdminPanel',
'isEmailVerified',
])
.orIgnore()
.values([
{
id: USER_DATA_SEED_IDS.TIM,
firstName: 'Tim',
lastName: 'Apple',
email: 'tim@apple.dev',
passwordHash:
'$2b$10$3LwXjJRtLsfx4hLuuXhxt.3mWgismTiZFCZSG3z9kDrSfsrBl0fT6', // tim@apple.dev
canImpersonate: true,
canAccessFullAdminPanel: true,
isEmailVerified: true,
},
{
id: USER_DATA_SEED_IDS.JONY,
firstName: 'Jony',
lastName: 'Ive',
email: 'jony.ive@apple.dev',
passwordHash:
'$2b$10$3LwXjJRtLsfx4hLuuXhxt.3mWgismTiZFCZSG3z9kDrSfsrBl0fT6', // tim@apple.dev
canImpersonate: true,
canAccessFullAdminPanel: true,
isEmailVerified: true,
},
{
id: USER_DATA_SEED_IDS.PHIL,
firstName: 'Phil',
lastName: 'Schiler',
email: 'phil.schiler@apple.dev',
passwordHash:
'$2b$10$3LwXjJRtLsfx4hLuuXhxt.3mWgismTiZFCZSG3z9kDrSfsrBl0fT6', // tim@apple.dev
canImpersonate: true,
canAccessFullAdminPanel: true,
isEmailVerified: true,
},
])
.execute();
};

View File

@ -0,0 +1,83 @@
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
import { DataSource } from 'typeorm';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { extractVersionMajorMinorPatch } from 'src/utils/version/extract-version-major-minor-patch';
const tableName = 'workspace';
export const SEED_APPLE_WORKSPACE_ID = '20202020-1c25-4d02-bf25-6aeccf7ea419';
export const SEED_ACME_WORKSPACE_ID = '3b8e6458-5fc1-4e63-8563-008ccddaa6db';
export type SeedWorkspaceArgs = {
dataSource: DataSource;
schemaName: string;
workspaceId: string;
appVersion: string | undefined;
};
const workspaceSeederFields = [
'id',
'displayName',
'subdomain',
'inviteHash',
'logo',
'activationStatus',
'version',
] as const satisfies (keyof Workspace)[];
type WorkspaceSeederFields = Pick<
Workspace,
(typeof workspaceSeederFields)[number]
>;
export const seedWorkspaces = async ({
schemaName,
dataSource,
workspaceId,
appVersion,
}: SeedWorkspaceArgs) => {
const version = extractVersionMajorMinorPatch(appVersion);
const workspaces: Record<string, WorkspaceSeederFields> = {
[SEED_APPLE_WORKSPACE_ID]: {
id: SEED_APPLE_WORKSPACE_ID,
displayName: 'Apple',
subdomain: 'apple',
inviteHash: 'apple.dev-invite-hash',
logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png',
activationStatus: WorkspaceActivationStatus.PENDING_CREATION, // will be set to active after default role creation
version: version,
},
[SEED_ACME_WORKSPACE_ID]: {
id: SEED_ACME_WORKSPACE_ID,
displayName: 'Acme',
subdomain: 'acme',
inviteHash: 'acme.dev-invite-hash',
logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png',
activationStatus: WorkspaceActivationStatus.PENDING_CREATION, // will be set to active after default role creation
version: version,
},
};
await dataSource
.createQueryBuilder()
.insert()
.into(`${schemaName}.${tableName}`, workspaceSeederFields)
.orIgnore()
.values(workspaces[workspaceId])
.execute();
};
export const deleteWorkspaces = async (
dataSource: DataSource,
schemaName: string,
workspaceId: string,
) => {
await dataSource
.createQueryBuilder()
.delete()
.from(`${schemaName}.${tableName}`)
.where(`${tableName}."id" = :id`, { id: workspaceId })
.execute();
};

View File

@ -0,0 +1,25 @@
type ApiKeyDataSeed = {
id: string;
name: string;
expiresAt: Date;
};
export const API_KEY_DATA_SEED_COLUMNS: (keyof ApiKeyDataSeed)[] = [
'id',
'name',
'expiresAt',
];
export const API_KEY_DATA_SEED_IDS = {
ID_1: '20202020-f401-4d8a-a731-64d007c27bad',
};
export const API_KEY_DATA_SEEDS: ApiKeyDataSeed[] = [
{
id: API_KEY_DATA_SEED_IDS.ID_1,
name: 'My api key',
expiresAt: new Date(
new Date().getTime() + 1000 * 60 * 60 * 24 * 365 * 100, // In 100 years
),
},
];

View File

@ -0,0 +1,36 @@
import { CONNECTED_ACCOUNT_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/connected-account-data-seeds.constant';
import { CalendarChannelVisibility } from 'src/modules/calendar/common/standard-objects/calendar-channel.workspace-entity';
type CalendarChannelDataSeed = {
id: string;
connectedAccountId: string;
handle: string;
visibility: CalendarChannelVisibility;
isContactAutoCreationEnabled: boolean;
isSyncEnabled: boolean;
};
export const CALENDAR_CHANNEL_DATA_SEED_COLUMNS: (keyof CalendarChannelDataSeed)[] =
[
'id',
'connectedAccountId',
'handle',
'visibility',
'isContactAutoCreationEnabled',
'isSyncEnabled',
];
export const CALENDAR_CHANNEL_DATA_SEED_IDS = {
TIM: '20202020-a40f-4faf-bb9f-c6f9945b8203',
};
export const CALENDAR_CHANNEL_DATA_SEEDS: CalendarChannelDataSeed[] = [
{
id: CALENDAR_CHANNEL_DATA_SEED_IDS.TIM,
connectedAccountId: CONNECTED_ACCOUNT_DATA_SEED_IDS.TIM,
handle: 'tim@apple.dev',
visibility: CalendarChannelVisibility.SHARE_EVERYTHING,
isContactAutoCreationEnabled: true,
isSyncEnabled: true,
},
];

View File

@ -0,0 +1,34 @@
import { CALENDAR_CHANNEL_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-channel-data-seeds.constant';
import { CALENDAR_EVENT_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-event-data-seeds.constant';
type CalendarChannelEventAssociationDataSeed = {
id: string;
calendarChannelId: string;
calendarEventId: string;
eventExternalId: string;
recurringEventExternalId: string;
};
export const CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEED_COLUMNS: (keyof CalendarChannelEventAssociationDataSeed)[] =
[
'id',
'calendarChannelId',
'calendarEventId',
'eventExternalId',
'recurringEventExternalId',
];
export const CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEED_IDS = {
ID_1: '20202020-0687-4c41-b707-ed1bfca972a2',
};
export const CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEEDS: CalendarChannelEventAssociationDataSeed[] =
[
{
id: CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEED_IDS.ID_1,
calendarChannelId: CALENDAR_CHANNEL_DATA_SEED_IDS.TIM,
calendarEventId: CALENDAR_EVENT_DATA_SEED_IDS.ID_1,
eventExternalId: 'exampleExternalId',
recurringEventExternalId: 'exampleRecurringExternalId',
},
];

View File

@ -0,0 +1,57 @@
type CalendarEventDataSeed = {
id: string;
title: string;
isCanceled: boolean;
isFullDay: boolean;
startsAt: string;
endsAt: string;
externalCreatedAt: string;
externalUpdatedAt: string;
description: string;
location: string;
iCalUID: string;
conferenceSolution: string;
conferenceLinkPrimaryLinkLabel: string;
conferenceLinkPrimaryLinkUrl: string;
};
export const CALENDAR_EVENT_DATA_SEED_COLUMNS: (keyof CalendarEventDataSeed)[] =
[
'id',
'title',
'isCanceled',
'isFullDay',
'startsAt',
'endsAt',
'externalCreatedAt',
'externalUpdatedAt',
'description',
'location',
'iCalUID',
'conferenceSolution',
'conferenceLinkPrimaryLinkLabel',
'conferenceLinkPrimaryLinkUrl',
];
export const CALENDAR_EVENT_DATA_SEED_IDS = {
ID_1: '20202020-1c0e-494c-a1b6-85b1c6fefaa5',
};
export const CALENDAR_EVENT_DATA_SEEDS: CalendarEventDataSeed[] = [
{
id: CALENDAR_EVENT_DATA_SEED_IDS.ID_1,
title: 'Meeting with Christoph',
isCanceled: false,
isFullDay: false,
startsAt: new Date(new Date().setHours(10, 0)).toISOString(),
endsAt: new Date(new Date().setHours(11, 0)).toISOString(),
externalCreatedAt: new Date().toISOString(),
externalUpdatedAt: new Date().toISOString(),
description: 'Discuss project progress',
location: 'Seattle',
iCalUID: 'event1@calendar.com',
conferenceSolution: 'Zoom',
conferenceLinkPrimaryLinkLabel: 'https://zoom.us/j/1234567890',
conferenceLinkPrimaryLinkUrl: 'https://zoom.us/j/1234567890',
},
];

View File

@ -0,0 +1,55 @@
import { CALENDAR_EVENT_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-event-data-seeds.constant';
import { PERSON_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/person-data-seeds.constant';
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
import { CalendarEventParticipantResponseStatus } from 'src/modules/calendar/common/standard-objects/calendar-event-participant.workspace-entity';
type CalendarEventParticipantDataSeed = {
id: string;
calendarEventId: string;
handle: string;
displayName: string;
isOrganizer: boolean;
responseStatus: CalendarEventParticipantResponseStatus;
personId: string | null;
workspaceMemberId: string | null;
};
export const CALENDAR_EVENT_PARTICIPANT_DATA_SEED_COLUMNS = [
'id',
'calendarEventId',
'handle',
'displayName',
'isOrganizer',
'responseStatus',
'personId',
'workspaceMemberId',
];
export const CALENDAR_EVENT_PARTICIPANT_DATA_SEED_IDS = {
ONE: '20202020-fb8f-4f0d-a36e-950e185401d4',
TWO: '20202020-0722-40d7-9e55-cb5d00cfb654',
};
export const CALENDAR_EVENT_PARTICIPANT_DATA_SEEDS: CalendarEventParticipantDataSeed[] =
[
{
id: CALENDAR_EVENT_PARTICIPANT_DATA_SEED_IDS.ONE,
calendarEventId: CALENDAR_EVENT_DATA_SEED_IDS.ID_1,
handle: 'christoph.calisto@linkedin.com',
displayName: 'Christoph Calisto',
isOrganizer: true,
responseStatus: CalendarEventParticipantResponseStatus.ACCEPTED,
personId: PERSON_DATA_SEED_IDS.ID_1,
workspaceMemberId: null,
},
{
id: CALENDAR_EVENT_PARTICIPANT_DATA_SEED_IDS.TWO,
calendarEventId: CALENDAR_EVENT_DATA_SEED_IDS.ID_1,
handle: 'tim@apple.com',
displayName: 'Tim Apple',
isOrganizer: false,
responseStatus: CalendarEventParticipantResponseStatus.ACCEPTED,
personId: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
},
];

View File

@ -0,0 +1,73 @@
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
type ConnectedAccountDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
lastSyncHistoryId: string;
accountOwnerId: string;
refreshToken: string;
accessToken: string;
provider: string;
handle: string;
};
export const CONNECTED_ACCOUNT_DATA_SEED_COLUMNS: (keyof ConnectedAccountDataSeed)[] =
[
'id',
'createdAt',
'updatedAt',
'deletedAt',
'lastSyncHistoryId',
'accountOwnerId',
'refreshToken',
'accessToken',
'provider',
'handle',
];
export const CONNECTED_ACCOUNT_DATA_SEED_IDS = {
TIM: '20202020-9ac0-4390-9a1a-ab4d2c4e1bb7',
JONY: '20202020-0cc8-4d60-a3a4-803245698908',
PHIL: '20202020-cafc-4323-908d-e5b42ad69fdf',
};
export const CONNECTED_ACCOUNT_DATA_SEEDS: ConnectedAccountDataSeed[] = [
{
id: CONNECTED_ACCOUNT_DATA_SEED_IDS.TIM,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
lastSyncHistoryId: 'exampleLastSyncHistory',
accountOwnerId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
refreshToken: 'exampleRefreshToken',
accessToken: 'exampleAccessToken',
provider: 'google',
handle: 'tim@apple.dev',
},
{
id: CONNECTED_ACCOUNT_DATA_SEED_IDS.JONY,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
lastSyncHistoryId: 'exampleLastSyncHistory',
accountOwnerId: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
refreshToken: 'exampleRefreshToken',
accessToken: 'exampleAccessToken',
provider: 'google',
handle: 'jony.ive@apple.dev',
},
{
id: CONNECTED_ACCOUNT_DATA_SEED_IDS.PHIL,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
lastSyncHistoryId: 'exampleLastSyncHistory',
accountOwnerId: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
refreshToken: 'exampleRefreshToken',
accessToken: 'exampleAccessToken',
provider: 'google',
handle: 'phil.schiler@apple.dev',
},
];

View File

@ -0,0 +1,82 @@
import { CONNECTED_ACCOUNT_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/connected-account-data-seeds.constant';
import {
MessageChannelSyncStage,
MessageChannelVisibility,
} from 'src/modules/messaging/common/standard-objects/message-channel.workspace-entity';
type MessageChannelDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
isContactAutoCreationEnabled: boolean;
type: string;
connectedAccountId: string;
handle: string;
isSyncEnabled: boolean;
visibility: MessageChannelVisibility;
syncStage: MessageChannelSyncStage;
};
export const MESSAGE_CHANNEL_DATA_SEED_COLUMNS: (keyof MessageChannelDataSeed)[] =
[
'id',
'createdAt',
'updatedAt',
'deletedAt',
'isContactAutoCreationEnabled',
'type',
'connectedAccountId',
'handle',
'isSyncEnabled',
'visibility',
'syncStage',
];
export const MESSAGE_CHANNEL_DATA_SEED_IDS = {
TIM: '20202020-9b80-4c2c-a597-383db48de1d6',
JONY: '20202020-5ffe-4b32-814a-983d5e4911cd',
PHIL: '20202020-e2f1-49b5-85d2-5d3a3386990c',
};
export const MESSAGE_CHANNEL_DATA_SEEDS: MessageChannelDataSeed[] = [
{
id: MESSAGE_CHANNEL_DATA_SEED_IDS.TIM,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
isContactAutoCreationEnabled: true,
type: 'email',
connectedAccountId: CONNECTED_ACCOUNT_DATA_SEED_IDS.TIM,
handle: 'tim@apple.dev',
isSyncEnabled: false,
visibility: MessageChannelVisibility.SHARE_EVERYTHING,
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
},
{
id: MESSAGE_CHANNEL_DATA_SEED_IDS.JONY,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
isContactAutoCreationEnabled: true,
type: 'email',
connectedAccountId: CONNECTED_ACCOUNT_DATA_SEED_IDS.JONY,
handle: 'jony.ive@apple.dev',
isSyncEnabled: false,
visibility: MessageChannelVisibility.SHARE_EVERYTHING,
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
},
{
id: MESSAGE_CHANNEL_DATA_SEED_IDS.PHIL,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
isContactAutoCreationEnabled: true,
type: 'email',
connectedAccountId: CONNECTED_ACCOUNT_DATA_SEED_IDS.PHIL,
handle: 'phil.schiler@apple.dev',
isSyncEnabled: false,
visibility: MessageChannelVisibility.SHARE_EVERYTHING,
syncStage: MessageChannelSyncStage.FULL_MESSAGE_LIST_FETCH_PENDING,
},
];

View File

@ -0,0 +1,71 @@
import { MESSAGE_CHANNEL_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/message-channel-data-seeds.constant';
import { MESSAGE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/message-data-seeds.constant';
import { MessageDirection } from 'src/modules/messaging/common/enums/message-direction.enum';
type MessageChannelMessageAssociationDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
messageThreadExternalId: string | null;
messageExternalId: string | null;
messageId: string;
messageChannelId: string;
direction: MessageDirection;
};
export const MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_COLUMNS: (keyof MessageChannelMessageAssociationDataSeed)[] =
[
'id',
'createdAt',
'updatedAt',
'deletedAt',
'messageThreadExternalId',
'messageExternalId',
'messageId',
'messageChannelId',
'direction',
];
export const MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_IDS = {
ID_1: '20202020-cc69-44ef-a82c-600c0dbf39ba',
ID_2: '20202020-d80e-4a13-b10b-72ba09082668',
ID_3: '20202020-e6ec-4c8a-b431-0901eaf395a9',
};
export const MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEEDS: MessageChannelMessageAssociationDataSeed[] =
[
{
id: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_IDS.ID_1,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
messageThreadExternalId: null,
messageExternalId: null,
messageId: MESSAGE_DATA_SEED_IDS.ID_1,
messageChannelId: MESSAGE_CHANNEL_DATA_SEED_IDS.TIM,
direction: MessageDirection.OUTGOING,
},
{
id: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_IDS.ID_2,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
messageThreadExternalId: null,
messageExternalId: null,
messageId: MESSAGE_DATA_SEED_IDS.ID_2,
messageChannelId: MESSAGE_CHANNEL_DATA_SEED_IDS.TIM,
direction: MessageDirection.OUTGOING,
},
{
id: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_IDS.ID_3,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
messageThreadExternalId: null,
messageExternalId: null,
messageId: MESSAGE_DATA_SEED_IDS.ID_3,
messageChannelId: MESSAGE_CHANNEL_DATA_SEED_IDS.TIM,
direction: MessageDirection.INCOMING,
},
];

View File

@ -0,0 +1,67 @@
import { MESSAGE_THREAD_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/message-thread-data-seeds.constant';
type MessageDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
receivedAt: Date;
text: string;
subject: string;
messageThreadId: string;
headerMessageId: string;
};
export const MESSAGE_DATA_SEED_COLUMNS: (keyof MessageDataSeed)[] = [
'id',
'createdAt',
'updatedAt',
'deletedAt',
'receivedAt',
'text',
'subject',
'messageThreadId',
'headerMessageId',
];
export const MESSAGE_DATA_SEED_IDS = {
ID_1: '20202020-2b8a-405d-8f42-e820ca921421',
ID_2: '20202020-04c8-4f24-93f2-764948e95014',
ID_3: '20202020-ac6b-4f86-87a2-5f5f9d1b6481',
};
export const MESSAGE_DATA_SEEDS: MessageDataSeed[] = [
{
id: MESSAGE_DATA_SEED_IDS.ID_1,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
receivedAt: new Date(),
text: 'Hello, \n I hope this email finds you well. I am writing to request a meeting. I believe it would be beneficial for both parties to collaborate and explore potential opportunities. Would you be available for a meeting sometime next week? Please let me know your availability, and I will arrange a suitable time. \n Looking forward to your response.\n Best regards',
subject: 'Meeting Request',
messageThreadId: MESSAGE_THREAD_DATA_SEED_IDS.ID_1,
headerMessageId: '99ef24a8-2b8a-405d-8f42-e820ca921421',
},
{
id: MESSAGE_DATA_SEED_IDS.ID_2,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
receivedAt: new Date(),
text: 'Good Morning,\n I am writing to inquire about information. Could you please provide me with details regarding this topic? \n Your assistance in this matter would be greatly appreciated. Thank you in advance for your prompt response. \n Best regards,Tim',
subject: 'Inquiry Regarding Topic',
messageThreadId: MESSAGE_THREAD_DATA_SEED_IDS.ID_2,
headerMessageId: '8f804a9a-04c8-4f24-93f2-764948e95014',
},
{
id: MESSAGE_DATA_SEED_IDS.ID_3,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
receivedAt: new Date(),
text: 'Good Evening,\nI wanted to extend my sincere gratitude for taking the time to meet with me earlier today. It was a pleasure discussing with you, and I am excited about the potential opportunities for collaboration. \n Please feel free to reach out if you have any further questions or require additional information. I look forward to our continued communication. Best regards.',
subject: 'Thank You for the Meeting',
messageThreadId: MESSAGE_THREAD_DATA_SEED_IDS.ID_1,
headerMessageId: '3939d68a-ac6b-4f86-87a2-5f5f9d1b6481',
},
];

View File

@ -0,0 +1,114 @@
import { MESSAGE_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/message-data-seeds.constant';
import { PERSON_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/person-data-seeds.constant';
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
type MessageParticipantDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
workspaceMemberId: string;
personId: string;
displayName: string;
handle: string;
role: string;
messageId: string;
};
export const MESSAGE_PARTICIPANT_DATA_SEED_COLUMNS: (keyof MessageParticipantDataSeed)[] =
[
'id',
'createdAt',
'updatedAt',
'deletedAt',
'workspaceMemberId',
'personId',
'displayName',
'handle',
'role',
'messageId',
];
export const MESSAGE_PARTICIPANT_DATA_SEED_IDS = {
ID_1: '20202020-0f2a-49d8-8aa2-ec8786153a0b',
ID_2: '20202020-4e83-41ec-93e2-fd70ff09f68c',
ID_3: '20202020-e716-4dd5-ac61-3315bc559e2d',
ID_4: '20202020-fc7d-4ad8-9aea-b78bcbf79cdd',
ID_5: '20202020-564c-4a3c-abbf-e942e8c3f9c9',
ID_6: '20202020-7e4a-489a-ba6b-1ae6b7d721ac',
};
export const MESSAGE_PARTICIPANT_DATA_SEEDS: MessageParticipantDataSeed[] = [
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_1,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_1,
displayName: 'Christoph',
handle: 'outgoing',
role: 'from',
messageId: MESSAGE_DATA_SEED_IDS.ID_1,
},
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_2,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_2,
displayName: 'Sylvie',
handle: 'incoming',
role: 'to',
messageId: MESSAGE_DATA_SEED_IDS.ID_1,
},
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_3,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_3,
displayName: 'Christopher',
handle: 'incoming',
role: 'to',
messageId: MESSAGE_DATA_SEED_IDS.ID_1,
},
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_4,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_1,
displayName: 'Christoph',
handle: 'outgoing',
role: 'from',
messageId: MESSAGE_DATA_SEED_IDS.ID_2,
},
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_5,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_2,
displayName: 'Sylvie',
handle: 'incoming',
role: 'to',
messageId: MESSAGE_DATA_SEED_IDS.ID_2,
},
{
id: MESSAGE_PARTICIPANT_DATA_SEED_IDS.ID_6,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
workspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
personId: PERSON_DATA_SEED_IDS.ID_3,
displayName: 'Christopher',
handle: 'incoming',
role: 'to',
messageId: MESSAGE_DATA_SEED_IDS.ID_2,
},
];

View File

@ -0,0 +1,44 @@
type MessageThreadDataSeed = {
id: string;
createdAt: Date;
updatedAt: Date;
deletedAt: Date | null;
};
export const MESSAGE_THREAD_DATA_SEED_COLUMNS: (keyof MessageThreadDataSeed)[] =
['id', 'createdAt', 'updatedAt', 'deletedAt'];
export const MESSAGE_THREAD_DATA_SEED_IDS = {
ID_1: '20202020-8bfa-453b-b99b-bc435a7d4da8',
ID_2: '20202020-634a-4fde-aa7c-28a0eaf203ca',
ID_3: '20202020-1b56-4f10-a2fa-2ccaddf81f6c',
ID_4: '20202020-d51c-485a-b1b6-ed7c63e05d72',
ID_5: '20202020-3f74-492d-a101-2a70f50a1645',
};
export const MESSAGE_THREAD_DATA_SEEDS: MessageThreadDataSeed[] = [
{
id: MESSAGE_THREAD_DATA_SEED_IDS.ID_1,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
},
{
id: MESSAGE_THREAD_DATA_SEED_IDS.ID_2,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
},
{
id: MESSAGE_THREAD_DATA_SEED_IDS.ID_3,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
},
{
id: MESSAGE_THREAD_DATA_SEED_IDS.ID_4,
createdAt: new Date(),
updatedAt: new Date(),
deletedAt: null,
},
];

View File

@ -0,0 +1,99 @@
import { COMPANY_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/company-data-seeds.constant';
import { PERSON_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/person-data-seeds.constant';
import { WORKSPACE_MEMBER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
type OpportunityDataSeed = {
id: string;
name: string;
amountAmountMicros: number;
amountCurrencyCode: string;
closeDate: Date;
stage: string;
position: number;
pointOfContactId: string;
companyId: string;
createdBySource: string;
createdByWorkspaceMemberId: string;
createdByName: string;
};
export const OPPORTUNITY_DATA_SEED_COLUMNS: (keyof OpportunityDataSeed)[] = [
'id',
'name',
'amountAmountMicros',
'amountCurrencyCode',
'closeDate',
'stage',
'position',
'pointOfContactId',
'companyId',
'createdBySource',
'createdByWorkspaceMemberId',
'createdByName',
];
export const OPPORTUNITY_DATA_SEED_IDS = {
ID_1: '20202020-be10-422b-a663-16bd3c2228e1',
ID_2: '20202020-0543-4cc2-9f96-95cc699960f2',
ID_3: '20202020-2f89-406f-90ea-180f433b2445',
ID_4: '20202020-35b1-4045-9cde-42f715148954',
};
export const OPPORTUNITY_DATA_SEEDS: OpportunityDataSeed[] = [
{
id: OPPORTUNITY_DATA_SEED_IDS.ID_1,
name: 'Opportunity 1',
amountAmountMicros: 100000,
amountCurrencyCode: 'USD',
closeDate: new Date(),
stage: 'NEW',
position: 1,
pointOfContactId: PERSON_DATA_SEED_IDS.ID_1,
companyId: COMPANY_DATA_SEED_IDS.ID_1,
createdBySource: 'MANUAL',
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
createdByName: 'Tim Cook',
},
{
id: OPPORTUNITY_DATA_SEED_IDS.ID_2,
name: 'Opportunity 2',
amountAmountMicros: 2000000,
amountCurrencyCode: 'USD',
closeDate: new Date(),
stage: 'MEETING',
position: 2,
pointOfContactId: PERSON_DATA_SEED_IDS.ID_2,
companyId: COMPANY_DATA_SEED_IDS.ID_2,
createdBySource: 'MANUAL',
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
createdByName: 'Tim Cook',
},
{
id: OPPORTUNITY_DATA_SEED_IDS.ID_3,
name: 'Opportunity 3',
amountAmountMicros: 300000,
amountCurrencyCode: 'USD',
closeDate: new Date(),
stage: 'PROPOSAL',
position: 3,
pointOfContactId: PERSON_DATA_SEED_IDS.ID_3,
companyId: COMPANY_DATA_SEED_IDS.ID_3,
createdBySource: 'MANUAL',
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
createdByName: 'Tim Cook',
},
{
id: OPPORTUNITY_DATA_SEED_IDS.ID_4,
name: 'Opportunity 4',
amountAmountMicros: 4000000,
amountCurrencyCode: 'USD',
closeDate: new Date(),
stage: 'PROPOSAL',
position: 4,
pointOfContactId: PERSON_DATA_SEED_IDS.ID_4,
companyId: COMPANY_DATA_SEED_IDS.ID_4,
createdBySource: 'MANUAL',
createdByWorkspaceMemberId: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
createdByName: '',
},
];

View File

@ -0,0 +1,204 @@
type PetDataSeed = {
id: string;
name: string;
species: string;
traits: string[];
comments: string;
age: number;
locationAddressStreet1: string;
locationAddressStreet2: string;
locationAddressCity: string;
locationAddressCountry: string;
locationAddressPostcode: string;
locationAddressState: string;
vetPhonePrimaryPhoneCallingCode: string;
vetPhonePrimaryPhoneCountryCode: string;
vetPhonePrimaryPhoneNumber: string;
vetEmailPrimaryEmail: string;
vetEmailAdditionalEmails: string;
birthday: string;
isGoodWithKids: boolean;
picturesPrimaryLinkUrl: string;
picturesPrimaryLinkLabel: string;
picturesSecondaryLinks: string;
averageCostOfKibblePerMonthAmountMicros: number;
averageCostOfKibblePerMonthCurrencyCode: string;
makesOwnerThinkOfFirstName: string;
makesOwnerThinkOfLastName: string;
soundSwag: string;
bio: string;
interestingFacts: string[];
extraData: string;
};
export const PET_DATA_SEED_COLUMNS: (keyof PetDataSeed)[] = [
'id',
'name',
'species',
'traits',
'comments',
'age',
'locationAddressStreet1',
'locationAddressStreet2',
'locationAddressCity',
'locationAddressCountry',
'locationAddressPostcode',
'locationAddressState',
'vetPhonePrimaryPhoneCallingCode',
'vetPhonePrimaryPhoneCountryCode',
'vetPhonePrimaryPhoneNumber',
'vetEmailPrimaryEmail',
'vetEmailAdditionalEmails',
'birthday',
'isGoodWithKids',
'picturesPrimaryLinkUrl',
'picturesPrimaryLinkLabel',
'picturesSecondaryLinks',
'averageCostOfKibblePerMonthAmountMicros',
'averageCostOfKibblePerMonthCurrencyCode',
'makesOwnerThinkOfFirstName',
'makesOwnerThinkOfLastName',
'soundSwag',
'bio',
'interestingFacts',
'extraData',
];
export const PET_DATA_SEED_IDS = {
ID_1: '20202020-0f2a-49d8-8aa2-ec8786153a0b',
};
export const PET_DATA_SEEDS: PetDataSeed[] = [
{
id: PET_DATA_SEED_IDS.ID_1,
name: 'Toby',
species: 'DOG',
traits: ['CURIOUS', 'FRIENDLY'],
comments: 'Needs to have people around.',
age: 3,
locationAddressStreet1: '513 Batz Fork',
locationAddressStreet2: '7344 Haley Loop',
locationAddressCity: 'Jacksonstad',
locationAddressCountry: 'United States',
locationAddressPostcode: '32048-5208',
locationAddressState: 'North Dakota',
vetPhonePrimaryPhoneCallingCode: '+33',
vetPhonePrimaryPhoneCountryCode: 'FR',
vetPhonePrimaryPhoneNumber: '789012345',
vetEmailPrimaryEmail: 'john@twenty.com',
vetEmailAdditionalEmails: JSON.stringify([
'tim@twenty.com',
'timapple@twenty.com',
'johnappletim@twenty.com',
]),
birthday: new Date('2019-01-01').toISOString(),
isGoodWithKids: false,
picturesPrimaryLinkUrl:
'https://images.unsplash.com/photo-1507146426996-ef05306b995a?q=80&w=3270&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
picturesPrimaryLinkLabel: 'Picture 1',
picturesSecondaryLinks: JSON.stringify([
{
url: 'https://images.unsplash.com/photo-1447684808650-354ae64db5b8?q=80&w=3267&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
label: 'Picture 2',
},
]),
averageCostOfKibblePerMonthAmountMicros: 2000000000,
averageCostOfKibblePerMonthCurrencyCode: 'USD',
makesOwnerThinkOfFirstName: 'Brad',
makesOwnerThinkOfLastName: 'Pitt',
soundSwag: 'RATING_3',
bio: '[{"id":"c2fc1fe1-8e44-41ce-a670-1819d1520fb1","type":"heading","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left","level":1},"content":[{"type":"text","text":"First encounter","styles":{}}],"children":[]},{"id":"064cb9b6-caf7-440e-8fbd-bcfa332fe909","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[{"type":"text","text":"It was a beautiful day; we went to the kennel because a friend of ours told us that the puppies were hoping to find their humans.","styles":{}}],"children":[]},{"id":"45a6c6d9-a561-49e6-b64a-4555dcb72084","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[],"children":[]},{"id":"3dcdfa35-d200-418d-8b67-0c8540c1fa69","type":"heading","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left","level":2},"content":[{"type":"text","text":"TODO","styles":{}}],"children":[]},{"id":"be99fc64-6cd4-4861-a81e-9096d92a6001","type":"checkListItem","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left","checked":true},"content":[{"type":"text","text":"Go to the vet","styles":{}}],"children":[]},{"id":"3ab3777a-4258-4396-8545-8acf19ebc113","type":"checkListItem","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left","checked":false},"content":[{"type":"text","text":"Buy kibbles","styles":{}}],"children":[]},{"id":"5c3a5427-4375-4154-be5a-61dceb55b87e","type":"checkListItem","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left","checked":false},"content":[{"type":"text","text":"Find a cozy spot for the basket","styles":{}}],"children":[]},{"id":"efca1bfb-59a7-4abe-8b71-a9dfd4a866cf","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[],"children":[]},{"id":"b8671315-309c-4da0-8371-8f5dc96ec42f","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[{"type":"text","text":"What it looked like when we met :","styles":{}}],"children":[]},{"id":"07758210-8772-4861-8398-a70b044ed42b","type":"image","props":{"backgroundColor":"default","textAlignment":"left","name":"photo-1530667912788-f976e8ee0bd5?q=80&w=3269&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D","url":"https://images.unsplash.com/photo-1530667912788-f976e8ee0bd5?q=80&w=3269&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D","caption":"","showPreview":true,"previewWidth":512},"children":[]},{"id":"a61a47fa-8635-4160-b336-8459cbe15351","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[{"type":"text","text":"Table of data :","styles":{}}],"children":[]},{"id":"28738ccc-5643-4497-ad66-e2e8c513bdfb","type":"table","props":{"textColor":"default","backgroundColor":"default"},"content":{"type":"tableContent","rows":[{"cells":[[{"type":"text","text":"Header 1","styles":{"bold":true}}],[{"type":"text","text":"Header 2","styles":{"bold":true}}],[{"type":"text","text":"Header 3","styles":{"bold":true}}]]},{"cells":[[{"type":"text","text":"Row 1 - Cell 1","styles":{}}],[{"type":"text","text":"Row 1 - Cell 2","styles":{}}],[{"type":"text","text":"Row 1 - Cell 3","styles":{}}]]}]},"children":[]},{"id":"3599afec-e653-41d8-97b6-c495afa3724e","type":"paragraph","props":{"textColor":"default","backgroundColor":"default","textAlignment":"left"},"content":[],"children":[]}]',
interestingFacts: [
'Worlds Best Sock Thief',
'Expert at Puppy Eyes',
'Fearless… Except Around Bananas',
'Signature Ear Flip',
],
extraData: JSON.stringify({
settingsOnVetSoftware: {
vetSoftware: 'VetLink',
settings: [
{
key: 'Vet name',
value: 'Dr. John Doe',
},
{
key: 'Vet phone',
value: '234-567-890',
},
{
key: 'Vet email',
value: 'asd@asd.com',
},
{
key: 'Vet address',
value:
'513 Batz Fork, 7344 Haley Loop, Jacksonstad, North Dakota, 32048-5208, United States',
},
],
},
additionalData: [
{
key: 'Weight',
value: '5kg',
},
{
key: 'Height',
value: '30cm',
},
{
key: 'Length',
value: '50cm',
},
{
key: 'Breed',
value: 'Golden Retriever',
},
{
key: 'Color',
value: 'Golden',
},
{
key: 'Eye color',
value: 'Brown',
},
{
key: 'Fur',
value: 'Long',
},
{
key: 'Tail',
value: 'Long',
},
{
key: 'Ears',
value: 'Long',
},
{
key: 'Paws',
value: 'Small',
},
{
key: 'Nose',
value: 'Wet',
},
{
key: 'Teeth',
value: 'White',
},
{
key: 'Habits',
value: 'Barks when someone is at the door',
},
{
key: 'Likes',
value: 'Belly rubs',
},
{
key: 'Dislikes',
value: 'Being alone',
},
],
}),
},
];

View File

@ -0,0 +1,66 @@
type SurveyResultDataSeed = {
id: string;
name: string;
score: number;
percentageOfCompletion: number;
participants: number;
averageEstimatedNumberOfAtomsInTheUniverse: string;
comments: string;
shortNotes: string;
};
export const SURVEY_RESULT_DATA_SEED_COLUMNS: (keyof SurveyResultDataSeed)[] = [
'id',
'name',
'score',
'percentageOfCompletion',
'participants',
'averageEstimatedNumberOfAtomsInTheUniverse',
'comments',
'shortNotes',
];
export const SURVEY_RESULT_DATA_SEED_IDS = {
ID_1: '20202020-0f2a-49d8-8aa2-ec8786153a0b',
ID_2: '20202020-4e83-41ec-93e2-fd70ff09f68c',
ID_3: '20202020-e716-4dd5-ac61-3315bc559e2d',
};
export const SURVEY_RESULT_DATA_SEEDS: SurveyResultDataSeed[] = [
{
id: SURVEY_RESULT_DATA_SEED_IDS.ID_1,
name: 'First survey results - 2021',
score: 0.26022134837694466,
percentageOfCompletion: 76.3561814092,
participants: 599,
averageEstimatedNumberOfAtomsInTheUniverse:
'78667671999742413888718514892176090137414339407788865817757694662213423853',
comments:
'Fuga agnosco patria volva aqua angustus utpote acquiro bestia. Abduco vorax volva agnosco alioqui. Cupiditas abbas aptus uterque bibo sonitus. Tergum carpo degero defaeco. Nostrum verumtamen tactus arbustum tui administratio. Terra sollers calculus blandior. Trans supra tricesimus. Utrum tenus comis adeo asporto sto quibusdam theologus suppono. Cursim casso alveus validus vapulus acer vis. Velum traho adipisci coerceo terminatio at allatus turbo adnuo blandior. Ante consectetur cedo cibo perferendis at amicitia degenero. Doloremque votum cupressus cerno stillicidium arcesso abundans antea sumo. Spoliatio asper solus. Vespillo distinctio ver truculenter torqueo vado aureus. Eaque bonus occaecati defungo defetiscor cibo. Thema ager usus verbum caute tergeo earum adipiscor vinculum. Delinquo tardus canonicus abbas amo confugo doloremque. Comburo quos cumque inflammatio dignissimos abstergo ventus cruentus. Tabula aliquid contego sono delectatio aeternus. Summopere crinis debitis stella conservo desipio termes vulgaris.',
shortNotes: 'verto ascit iure tribuo vulnero',
},
{
id: SURVEY_RESULT_DATA_SEED_IDS.ID_2,
name: 'With only people from the US',
score: 0.07128839939832687,
percentageOfCompletion: 61.6284981836,
participants: 575,
averageEstimatedNumberOfAtomsInTheUniverse:
'58714201303231867082632874445965836504227665636297405101762256297406500076',
comments:
'Benevolentia valens caecus triduana. Cerno curiositas amita. Urbs urbs tertius iure spes succedo aspernatur culpa caute commodo. Cohaero voluptas amplexus denuo caelestis deprimo cresco cognatus aranea. Tabula perferendis ullus taedium vulnero stella corrupti testimonium. Ventosus ars abundans coniuratio. Cohibeo turba apostolus cunae tutamen. Audacia quod benevolentia charisma. Beatus consequuntur uterque crustulum valetudo spes vicinus. Tardus curso crinis ambulo cupiditate cras ad basium volup. Trepide dapifer theologus volva. Urbanus audacia ver aeger clamo animus adsidue error thorax. Ut centum volutabrum virgo summisse earum. Campana bos adulatio candidus tabgo tempore caries coadunatio. Cenaculum absque sustineo angustus quisquam auctus laudantium carbo stella. Conservo thymbra asperiores coaegresco vergo. Cubicularis canis solio. Tener vestrum iure claustrum velum aperte crinis ascisco clarus clam. Vinco ademptio absum. Verto desolo depraedor error coadunatio.',
shortNotes: 'tres tantillus vado aequus ago',
},
{
id: SURVEY_RESULT_DATA_SEED_IDS.ID_3,
name: 'People who like cats',
score: 0.1480973360594362,
percentageOfCompletion: 72.4289541366,
participants: 590,
averageEstimatedNumberOfAtomsInTheUniverse:
'51790645279092482632713239096036038617511762830423654232543291815995800207',
comments:
'Omnis careo ait praesentium inventore amet stips versus. Charisma demens vergo ex tibi desolo harum valens urbs abeo. Subnecto tantum tenax. Esse aduro caste comprehendo color bellicus excepturi tego coniuratio stella. Cogo cognatus cogo acerbitas aro. Asper cohibeo tam venustas arma antea studio eveniet casus. Numquam benevolentia voco celer. Defungo arcesso viridis veritas adsuesco desparatus patria tondeo canonicus stillicidium. Clamo truculenter vix allatus succedo depereo aestivus praesentium. Spiritus comes adipisci. Atrocitas virtus alveus strenuus. Repellat thermae aptus placeat aut. Ambitus tunc convoco adulatio averto. Agnitio aegrotatio aequus decumbo conventus. Valens adulatio ad voluptatibus conspergo vallum tredecim correptius. Celo aranea umquam. A abscido vigor virtus tristis cavus. Truculenter natus bonus sollers vulgivagus amita. Occaecati illo voco terga carcer commodo. Succurro vociferor bene vere accusamus defluo at videlicet aranea deleniti.',
shortNotes: 'aeneus armarium conventus curto rerum',
},
];

View File

@ -0,0 +1,58 @@
import { USER_DATA_SEED_IDS } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-users.util';
type WorkspaceMemberDataSeed = {
id: string;
nameFirstName: string;
nameLastName: string;
locale: string;
colorScheme: string;
userEmail: string;
userId: string;
};
export const WORKSPACE_MEMBER_DATA_SEED_COLUMNS: (keyof WorkspaceMemberDataSeed)[] =
[
'id',
'nameFirstName',
'nameLastName',
'locale',
'colorScheme',
'userEmail',
'userId',
];
export const WORKSPACE_MEMBER_DATA_SEED_IDS = {
TIM: '20202020-0687-4c41-b707-ed1bfca972a7',
JONY: '20202020-77d5-4cb6-b60a-f4a835a85d61',
PHIL: '20202020-1553-45c6-a028-5a9064cce07f',
};
export const WORKSPACE_MEMBER_DATA_SEEDS: WorkspaceMemberDataSeed[] = [
{
id: WORKSPACE_MEMBER_DATA_SEED_IDS.TIM,
nameFirstName: 'Tim',
nameLastName: 'Apple',
locale: 'en',
colorScheme: 'Light',
userEmail: 'tim@apple.dev',
userId: USER_DATA_SEED_IDS.TIM,
},
{
id: WORKSPACE_MEMBER_DATA_SEED_IDS.JONY,
nameFirstName: 'Jony',
nameLastName: 'Ive',
locale: 'en',
colorScheme: 'Light',
userEmail: 'jony.ive@apple.dev',
userId: USER_DATA_SEED_IDS.JONY,
},
{
id: WORKSPACE_MEMBER_DATA_SEED_IDS.PHIL,
nameFirstName: 'Phil',
nameLastName: 'Schiler',
locale: 'en',
colorScheme: 'Light',
userEmail: 'phil.schiler@apple.dev',
userId: USER_DATA_SEED_IDS.PHIL,
},
];

View File

@ -0,0 +1,250 @@
import { Injectable } from '@nestjs/common';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager';
import { shouldSeedWorkspaceFavorite } from 'src/engine/utils/should-seed-workspace-favorite';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import {
API_KEY_DATA_SEED_COLUMNS,
API_KEY_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/api-key-data-seeds.constant';
import {
CALENDAR_CHANNEL_DATA_SEED_COLUMNS,
CALENDAR_CHANNEL_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-channel-data-seeds.constant';
import {
CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEED_COLUMNS,
CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-channel-event-association-data-seeds.constant';
import {
CALENDAR_EVENT_DATA_SEED_COLUMNS,
CALENDAR_EVENT_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-event-data-seeds.constant';
import {
CALENDAR_EVENT_PARTICIPANT_DATA_SEED_COLUMNS,
CALENDAR_EVENT_PARTICIPANT_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/calendar-event-participant-data-seeds.constant';
import {
COMPANY_DATA_SEED_COLUMNS,
COMPANY_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/company-data-seeds.constant';
import {
CONNECTED_ACCOUNT_DATA_SEED_COLUMNS,
CONNECTED_ACCOUNT_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/connected-account-data-seeds.constant';
import {
MESSAGE_CHANNEL_DATA_SEED_COLUMNS,
MESSAGE_CHANNEL_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/message-channel-data-seeds.constant';
import {
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_COLUMNS,
MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/message-channel-message-association-data-seeds.constant';
import {
MESSAGE_DATA_SEED_COLUMNS,
MESSAGE_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/message-data-seeds.constant';
import {
MESSAGE_PARTICIPANT_DATA_SEED_COLUMNS,
MESSAGE_PARTICIPANT_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/message-participant-data-seeds.constant';
import {
MESSAGE_THREAD_DATA_SEED_COLUMNS,
MESSAGE_THREAD_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/message-thread-data-seeds.constant';
import {
OPPORTUNITY_DATA_SEED_COLUMNS,
OPPORTUNITY_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/opportunity-data-seeds.constant';
import {
PERSON_DATA_SEED_COLUMNS,
PERSON_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/person-data-seeds.constant';
import {
PET_DATA_SEED_COLUMNS,
PET_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/pet-data-seeds.constant';
import {
SURVEY_RESULT_DATA_SEED_COLUMNS,
SURVEY_RESULT_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/survey-result-data-seeds.constant';
import {
WORKSPACE_MEMBER_DATA_SEED_COLUMNS,
WORKSPACE_MEMBER_DATA_SEEDS,
} from 'src/engine/workspace-manager/dev-seeder/data/constants/workspace-member-data-seeds.constant';
import { prefillViews } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-views';
import { prefillWorkspaceFavorites } from 'src/engine/workspace-manager/standard-objects-prefill-data/prefill-workspace-favorites';
const RECORD_SEEDS_CONFIGS = [
{
tableName: 'workspaceMember',
pgColumns: WORKSPACE_MEMBER_DATA_SEED_COLUMNS,
recordSeeds: WORKSPACE_MEMBER_DATA_SEEDS,
},
{
tableName: 'company',
pgColumns: COMPANY_DATA_SEED_COLUMNS,
recordSeeds: COMPANY_DATA_SEEDS,
},
{
tableName: 'person',
pgColumns: PERSON_DATA_SEED_COLUMNS,
recordSeeds: PERSON_DATA_SEEDS,
},
{
tableName: 'opportunity',
pgColumns: OPPORTUNITY_DATA_SEED_COLUMNS,
recordSeeds: OPPORTUNITY_DATA_SEEDS,
},
{
tableName: 'apiKey',
pgColumns: API_KEY_DATA_SEED_COLUMNS,
recordSeeds: API_KEY_DATA_SEEDS,
},
{
tableName: 'connectedAccount',
pgColumns: CONNECTED_ACCOUNT_DATA_SEED_COLUMNS,
recordSeeds: CONNECTED_ACCOUNT_DATA_SEEDS,
},
{
tableName: 'calendarChannel',
pgColumns: CALENDAR_CHANNEL_DATA_SEED_COLUMNS,
recordSeeds: CALENDAR_CHANNEL_DATA_SEEDS,
},
{
tableName: 'calendarEvent',
pgColumns: CALENDAR_EVENT_DATA_SEED_COLUMNS,
recordSeeds: CALENDAR_EVENT_DATA_SEEDS,
},
{
tableName: 'calendarChannelEventAssociation',
pgColumns: CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEED_COLUMNS,
recordSeeds: CALENDAR_CHANNEL_EVENT_ASSOCIATION_DATA_SEEDS,
},
{
tableName: 'calendarEventParticipant',
pgColumns: CALENDAR_EVENT_PARTICIPANT_DATA_SEED_COLUMNS,
recordSeeds: CALENDAR_EVENT_PARTICIPANT_DATA_SEEDS,
},
{
tableName: 'messageChannel',
pgColumns: MESSAGE_CHANNEL_DATA_SEED_COLUMNS,
recordSeeds: MESSAGE_CHANNEL_DATA_SEEDS,
},
{
tableName: 'messageThread',
pgColumns: MESSAGE_THREAD_DATA_SEED_COLUMNS,
recordSeeds: MESSAGE_THREAD_DATA_SEEDS,
},
{
tableName: 'message',
pgColumns: MESSAGE_DATA_SEED_COLUMNS,
recordSeeds: MESSAGE_DATA_SEEDS,
},
{
tableName: 'messageChannelMessageAssociation',
pgColumns: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEED_COLUMNS,
recordSeeds: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_DATA_SEEDS,
},
{
tableName: 'messageParticipant',
pgColumns: MESSAGE_PARTICIPANT_DATA_SEED_COLUMNS,
recordSeeds: MESSAGE_PARTICIPANT_DATA_SEEDS,
},
{
tableName: '_pet',
pgColumns: PET_DATA_SEED_COLUMNS,
recordSeeds: PET_DATA_SEEDS,
},
{
tableName: '_surveyResult',
pgColumns: SURVEY_RESULT_DATA_SEED_COLUMNS,
recordSeeds: SURVEY_RESULT_DATA_SEEDS,
},
];
@Injectable()
export class DevSeederDataService {
constructor(
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
private readonly objectMetadataService: ObjectMetadataService,
) {}
public async seed({
schemaName,
workspaceId,
}: {
schemaName: string;
workspaceId: string;
}) {
const mainDataSource =
await this.workspaceDataSourceService.connectToMainDataSource();
if (!mainDataSource) {
throw new Error('Could not connect to main data source');
}
const objectMetadataItems =
await this.objectMetadataService.findManyWithinWorkspace(workspaceId);
await mainDataSource.transaction(
async (entityManager: WorkspaceEntityManager) => {
for (const recordSeedsConfig of RECORD_SEEDS_CONFIGS) {
await this.seedRecords({
entityManager,
schemaName,
tableName: recordSeedsConfig.tableName,
pgColumns: recordSeedsConfig.pgColumns,
recordSeeds: recordSeedsConfig.recordSeeds,
});
}
const viewDefinitionsWithId = await prefillViews(
entityManager,
schemaName,
objectMetadataItems,
);
await prefillWorkspaceFavorites(
viewDefinitionsWithId
.filter(
(view) =>
view.key === 'INDEX' &&
shouldSeedWorkspaceFavorite(
view.objectMetadataId,
objectMetadataItems,
),
)
.map((view) => view.id),
entityManager,
schemaName,
);
},
);
}
private async seedRecords({
entityManager,
schemaName,
tableName,
pgColumns,
recordSeeds,
}: {
entityManager: WorkspaceEntityManager;
schemaName: string;
tableName: string;
pgColumns: string[];
recordSeeds: Record<string, unknown>[];
}) {
await entityManager
.createQueryBuilder(undefined, undefined, undefined, {
shouldBypassPermissionChecks: true,
})
.insert()
.into(`${schemaName}.${tableName}`, pgColumns)
.orIgnore()
.values(recordSeeds)
.returning('*')
.execute();
}
}

View File

@ -0,0 +1,42 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TypeORMModule } from 'src/database/typeorm/typeorm.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
import { DevSeederPermissionsService } from 'src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service';
import { DevSeederDataService } from 'src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service';
import { DevSeederMetadataService } from 'src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service';
import { DevSeederService } from 'src/engine/workspace-manager/dev-seeder/services/dev-seeder.service';
import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module';
@Module({
imports: [
ObjectMetadataModule,
FieldMetadataModule,
WorkspaceDataSourceModule,
WorkspaceCacheStorageModule,
TypeORMModule,
DataSourceModule,
RoleModule,
UserRoleModule,
FeatureFlagModule,
WorkspaceSyncMetadataModule,
TypeOrmModule.forFeature([Workspace], 'core'),
],
exports: [DevSeederService],
providers: [
DevSeederService,
DevSeederMetadataService,
DevSeederPermissionsService,
DevSeederDataService,
],
})
export class DevSeederModule {}

View File

@ -0,0 +1,68 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
export const COMPANY_CUSTOM_FIELD_SEEDS: FieldMetadataSeed[] = [
{
type: FieldMetadataType.TEXT,
name: 'tagline',
label: 'Tagline',
description: "Company's Tagline",
icon: 'IconAdCircle',
isActive: true,
isNullable: false,
isUnique: false,
defaultValue: "''",
},
{
type: FieldMetadataType.LINKS,
name: 'introVideo',
label: 'Intro Video',
description: "Company's Intro Video",
icon: 'IconVideo',
isActive: true,
isNullable: true,
isUnique: false,
},
{
type: FieldMetadataType.MULTI_SELECT,
name: 'workPolicy',
label: 'Work Policy',
description: "Company's Work Policy",
icon: 'IconHome',
isActive: true,
isNullable: true,
isUnique: false,
options: [
{
color: 'green',
label: 'On-Site',
position: 0,
value: 'ON_SITE',
},
{
color: 'turquoise',
label: 'Hybrid',
position: 1,
value: 'HYBRID',
},
{
color: 'sky',
label: 'Remote Work',
position: 2,
value: 'REMOTE_WORK',
},
],
},
{
type: FieldMetadataType.BOOLEAN,
name: 'visaSponsorship',
label: 'Visa Sponsorship',
description: "Company's Visa Sponsorship Policy",
icon: 'IconBrandVisa',
isActive: true,
isNullable: true,
isUnique: false,
defaultValue: false,
},
];

View File

@ -0,0 +1,99 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
export const PERSON_CUSTOM_FIELD_SEEDS: FieldMetadataSeed[] = [
{
type: FieldMetadataType.TEXT,
name: 'intro',
label: 'Intro',
description: "Contact's Intro",
icon: 'IconNote',
isActive: true,
isNullable: true,
isUnique: false,
},
{
type: FieldMetadataType.PHONES,
name: 'whatsapp',
label: 'Whatsapp',
description: "Contact's Whatsapp Number",
icon: 'IconBrandWhatsapp',
isActive: true,
isNullable: false,
isUnique: false,
defaultValue: {
primaryPhoneNumber: "''",
primaryPhoneCountryCode: "'FR'",
primaryPhoneCallingCode: "'+33'",
additionalPhones: null,
},
},
{
type: FieldMetadataType.MULTI_SELECT,
name: 'workPreference',
label: 'Work Preference',
description: "Person's Work Preference",
icon: 'IconHome',
isActive: true,
isNullable: true,
isUnique: false,
options: [
{
color: 'green',
label: 'On-Site',
position: 0,
value: 'ON_SITE',
},
{
color: 'turquoise',
label: 'Hybrid',
position: 1,
value: 'HYBRID',
},
{
color: 'sky',
label: 'Remote Work',
position: 2,
value: 'REMOTE_WORK',
},
],
},
{
type: FieldMetadataType.RATING,
name: 'performanceRating',
label: 'Performance Rating',
description: "Person's Performance Rating",
icon: 'IconStars',
isActive: true,
isNullable: true,
isUnique: false,
options: [
{
label: '1',
value: 'RATING_1',
position: 0,
},
{
label: '2',
value: 'RATING_2',
position: 1,
},
{
label: '3',
value: 'RATING_3',
position: 2,
},
{
label: '4',
value: 'RATING_4',
position: 3,
},
{
label: '5',
value: 'RATING_5',
position: 4,
},
],
},
];

View File

@ -0,0 +1,107 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
export const PET_CUSTOM_FIELD_SEEDS: FieldMetadataSeed[] = [
{
type: FieldMetadataType.SELECT,
label: 'Species',
name: 'species',
options: [
{ label: 'Dog', value: 'DOG', position: 0, color: 'blue' },
{ label: 'Cat', value: 'CAT', position: 1, color: 'red' },
{ label: 'Bird', value: 'BIRD', position: 2, color: 'green' },
{ label: 'Fish', value: 'FISH', position: 3, color: 'yellow' },
{ label: 'Rabbit', value: 'RABBIT', position: 4, color: 'purple' },
{ label: 'Hamster', value: 'HAMSTER', position: 5, color: 'orange' },
],
},
{
type: FieldMetadataType.MULTI_SELECT,
label: 'Traits',
name: 'traits',
options: [
{ label: 'Playful', value: 'PLAYFUL', position: 0, color: 'blue' },
{ label: 'Friendly', value: 'FRIENDLY', position: 1, color: 'red' },
{
label: 'Protective',
value: 'PROTECTIVE',
position: 2,
color: 'green',
},
{ label: 'Shy', value: 'SHY', position: 3, color: 'yellow' },
{ label: 'Brave', value: 'BRAVE', position: 4, color: 'purple' },
{ label: 'Curious', value: 'CURIOUS', position: 5, color: 'orange' },
],
},
{
type: FieldMetadataType.TEXT,
label: 'Comments',
name: 'comments',
},
{
type: FieldMetadataType.NUMBER,
label: 'Age',
name: 'age',
},
{
type: FieldMetadataType.ADDRESS,
label: 'Location',
name: 'location',
},
{
type: FieldMetadataType.PHONES,
label: 'Vet phone',
name: 'vetPhone',
},
{
type: FieldMetadataType.EMAILS,
label: 'Vet email',
name: 'vetEmail',
},
{
type: FieldMetadataType.DATE,
label: 'Birthday',
name: 'birthday',
},
{
type: FieldMetadataType.BOOLEAN,
label: 'Is good with kids',
name: 'isGoodWithKids',
},
{
type: FieldMetadataType.LINKS,
label: 'Pictures',
name: 'pictures',
},
{
type: FieldMetadataType.CURRENCY,
label: 'Average cost of kibble per month',
name: 'averageCostOfKibblePerMonth',
},
{
type: FieldMetadataType.FULL_NAME,
label: 'Makes its owner think of',
name: 'makesOwnerThinkOf',
},
{
type: FieldMetadataType.RATING,
label: 'Sound swag (bark style, meow style, etc.)',
name: 'soundSwag',
},
{
type: FieldMetadataType.RICH_TEXT,
label: 'Bio',
name: 'bio',
},
{
type: FieldMetadataType.ARRAY,
label: 'Interesting facts',
name: 'interestingFacts',
},
{
type: FieldMetadataType.RAW_JSON,
label: 'Extra data',
name: 'extraData',
},
];

View File

@ -0,0 +1,63 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { NumberDataType } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata-settings.interface';
import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
import { FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
export const SURVEY_RESULT_CUSTOM_FIELD_SEEDS: FieldMetadataSeed[] = [
{
type: FieldMetadataType.NUMBER,
label: 'Score (Float 3 decimals)',
name: 'score',
settings: {
dataType: NumberDataType.FLOAT,
decimals: 3,
type: 'number',
},
} as FieldMetadataDTO<FieldMetadataType.NUMBER>,
{
type: FieldMetadataType.NUMBER,
label: 'Percentage of completion (Float 3 decimals + percentage)',
name: 'percentageOfCompletion',
settings: {
dataType: NumberDataType.FLOAT,
decimals: 6,
type: 'percentage',
},
} as FieldMetadataDTO<FieldMetadataType.NUMBER>,
{
type: FieldMetadataType.NUMBER,
label: 'Participants (Int)',
name: 'participants',
settings: {
dataType: NumberDataType.INT,
type: 'number',
},
} as FieldMetadataDTO<FieldMetadataType.NUMBER>,
{
type: FieldMetadataType.NUMBER,
label: 'Average estimated number of atoms in the universe (BigInt)',
name: 'averageEstimatedNumberOfAtomsInTheUniverse',
settings: {
dataType: NumberDataType.BIGINT,
type: 'number',
},
} as FieldMetadataDTO<FieldMetadataType.NUMBER>,
{
type: FieldMetadataType.TEXT,
label: 'Comments (Max 5 rows)',
name: 'comments',
settings: {
displayedMaxRows: 5,
},
} as FieldMetadataDTO<FieldMetadataType.TEXT>,
{
type: FieldMetadataType.TEXT,
label: 'Short notes (Max 1 row)',
name: 'shortNotes',
settings: {
displayedMaxRows: 1,
},
} as FieldMetadataDTO<FieldMetadataType.TEXT>,
];

View File

@ -0,0 +1,9 @@
import { ObjectMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/object-metadata-seed.type';
export const PET_CUSTOM_OBJECT_SEED: ObjectMetadataSeed = {
labelPlural: 'Pets',
labelSingular: 'Pet',
namePlural: 'pets',
nameSingular: 'pet',
icon: 'IconCat',
};

View File

@ -0,0 +1,11 @@
import { ObjectMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/object-metadata-seed.type';
export const ROCKET_CUSTOM_OBJECT_SEED: ObjectMetadataSeed = {
labelPlural: 'Rockets',
labelSingular: 'Rocket',
namePlural: 'rockets',
nameSingular: 'rocket',
icon: 'IconRocket',
description: 'A rocket',
isRemote: false,
};

View File

@ -0,0 +1,9 @@
import { ObjectMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/object-metadata-seed.type';
export const SURVEY_RESULT_CUSTOM_OBJECT_SEED: ObjectMetadataSeed = {
labelPlural: 'Survey results',
labelSingular: 'Survey result',
namePlural: 'surveyResults',
nameSingular: 'surveyResult',
icon: 'IconRulerMeasure',
};

View File

@ -0,0 +1,115 @@
import { Injectable } from '@nestjs/common';
import { DataSourceEntity } from 'src/engine/metadata-modules/data-source/data-source.entity';
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { COMPANY_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/company-custom-field-seeds.constant';
import { PERSON_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/person-custom-field-seeds.constant';
import { PET_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/pet-custom-field-seeds.constant';
import { SURVEY_RESULT_CUSTOM_FIELD_SEEDS } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-fields/constants/survey-results-field-seeds.constant';
import { PET_CUSTOM_OBJECT_SEED } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-objects/constants/pet-custom-object-seed.constant';
import { ROCKET_CUSTOM_OBJECT_SEED } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-objects/constants/rocket-custom-object-seed.constant';
import { SURVEY_RESULT_CUSTOM_OBJECT_SEED } from 'src/engine/workspace-manager/dev-seeder/metadata/custom-objects/constants/survey-results-object-seed.constant';
import { FieldMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/field-metadata-seed.type';
import { ObjectMetadataSeed } from 'src/engine/workspace-manager/dev-seeder/metadata/types/object-metadata-seed.type';
@Injectable()
export class DevSeederMetadataService {
constructor(
private readonly objectMetadataService: ObjectMetadataService,
private readonly fieldMetadataService: FieldMetadataService,
) {}
public async seed({
dataSourceMetadata,
workspaceId,
}: {
dataSourceMetadata: DataSourceEntity;
workspaceId: string;
}) {
await this.seedCustomObject({
dataSourceId: dataSourceMetadata.id,
workspaceId,
objectMetadataSeed: ROCKET_CUSTOM_OBJECT_SEED,
});
await this.seedCustomObject({
dataSourceId: dataSourceMetadata.id,
workspaceId,
objectMetadataSeed: PET_CUSTOM_OBJECT_SEED,
});
await this.seedCustomFields({
workspaceId,
objectMetadataNameSingular: PET_CUSTOM_OBJECT_SEED.nameSingular,
fieldMetadataSeeds: PET_CUSTOM_FIELD_SEEDS,
});
await this.seedCustomObject({
dataSourceId: dataSourceMetadata.id,
workspaceId,
objectMetadataSeed: SURVEY_RESULT_CUSTOM_OBJECT_SEED,
});
await this.seedCustomFields({
workspaceId,
objectMetadataNameSingular: SURVEY_RESULT_CUSTOM_OBJECT_SEED.nameSingular,
fieldMetadataSeeds: SURVEY_RESULT_CUSTOM_FIELD_SEEDS,
});
await this.seedCustomFields({
workspaceId,
objectMetadataNameSingular: 'company',
fieldMetadataSeeds: COMPANY_CUSTOM_FIELD_SEEDS,
});
await this.seedCustomFields({
workspaceId,
objectMetadataNameSingular: 'person',
fieldMetadataSeeds: PERSON_CUSTOM_FIELD_SEEDS,
});
}
private async seedCustomObject({
dataSourceId,
workspaceId,
objectMetadataSeed,
}: {
dataSourceId: string;
workspaceId: string;
objectMetadataSeed: ObjectMetadataSeed;
}): Promise<void> {
await this.objectMetadataService.createOne({
...objectMetadataSeed,
dataSourceId,
workspaceId,
});
}
private async seedCustomFields({
workspaceId,
objectMetadataNameSingular,
fieldMetadataSeeds,
}: {
workspaceId: string;
objectMetadataNameSingular: string;
fieldMetadataSeeds: FieldMetadataSeed[];
}): Promise<void> {
const objectMetadata =
await this.objectMetadataService.findOneWithinWorkspace(workspaceId, {
where: { nameSingular: objectMetadataNameSingular },
});
if (!objectMetadata) {
throw new Error('Object metadata not found');
}
await this.fieldMetadataService.createMany(
fieldMetadataSeeds.map((fieldMetadataSeed) => ({
...fieldMetadataSeed,
objectMetadataId: objectMetadata.id,
workspaceId,
})),
);
}
}

View File

@ -0,0 +1,6 @@
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
export type FieldMetadataSeed = Omit<
CreateFieldInput,
'objectMetadataId' | 'workspaceId'
>;

View File

@ -0,0 +1,6 @@
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
export type ObjectMetadataSeed = Omit<
CreateObjectInput,
'workspaceId' | 'dataSourceId' | 'fields'
>;

View File

@ -0,0 +1,83 @@
import { Injectable, Logger } from '@nestjs/common';
import { TypeORMService } from 'src/database/typeorm/typeorm.service';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { DevSeederPermissionsService } from 'src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service';
import { seedCoreSchema } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-core-schema.util';
import { DevSeederDataService } from 'src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service';
import { DevSeederMetadataService } from 'src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service';
import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service';
@Injectable()
export class DevSeederService {
private readonly logger = new Logger(DevSeederService.name);
constructor(
private readonly typeORMService: TypeORMService,
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
private readonly twentyConfigService: TwentyConfigService,
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
private readonly dataSourceService: DataSourceService,
private readonly featureFlagService: FeatureFlagService,
private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService,
private readonly devSeederMetadataService: DevSeederMetadataService,
private readonly devSeederPermissionsService: DevSeederPermissionsService,
private readonly devSeederDataService: DevSeederDataService,
) {}
public async seedDev(workspaceId: string): Promise<void> {
const mainDataSource = this.typeORMService.getMainDataSource();
if (!mainDataSource) {
throw new Error('Could not connect to workspace data source');
}
const isBillingEnabled = this.twentyConfigService.get('IS_BILLING_ENABLED');
const appVersion = this.twentyConfigService.get('APP_VERSION');
await seedCoreSchema({
dataSource: mainDataSource,
workspaceId,
seedBilling: isBillingEnabled,
appVersion,
});
const schemaName =
await this.workspaceDataSourceService.createWorkspaceDBSchema(
workspaceId,
);
const dataSourceMetadata =
await this.dataSourceService.createDataSourceMetadata(
workspaceId,
schemaName,
);
const featureFlags =
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
await this.workspaceSyncMetadataService.synchronize({
workspaceId: workspaceId,
dataSourceId: dataSourceMetadata.id,
featureFlags,
});
await this.devSeederMetadataService.seed({
dataSourceMetadata,
workspaceId,
});
await this.devSeederPermissionsService.initPermissions(workspaceId);
await this.devSeederDataService.seed({
schemaName: dataSourceMetadata.schema,
workspaceId,
});
await this.workspaceCacheStorageService.flush(workspaceId, undefined);
}
}